2
This commit is contained in:
		| @@ -0,0 +1,94 @@ | ||||
| <template> | ||||
|   <section class="approval-manage"> | ||||
|     <ai-list v-if="showList"> | ||||
|       <template slot="title"> | ||||
|         <ai-title title="审批管理" :isShowBottomBorder="false"></ai-title> | ||||
|       </template> | ||||
|       <template slot="tabs"> | ||||
|         <el-tabs class="tabs-page" v-model="currIndex"> | ||||
|           <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" :listType="tab.value" @goPage="goPage"/> | ||||
|           </el-tab-pane> | ||||
|         </el-tabs> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <component v-if="!showList" :is="currentPage" :instance="instance" :listType="currentTab.value" :dict="dict" | ||||
|                :permissions="permissions" :detail="detail" @goBack="goBack"></component> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import forMyApproval from "./components/forMyApproval"; | ||||
|   import approvalDetail from "./components/approvalDetail"; | ||||
|  | ||||
|   export default { | ||||
|     name: "AppApprovalManage", | ||||
|     label: "审批管理", | ||||
|     components: {approvalDetail}, | ||||
|     provide() { | ||||
|       return { | ||||
|         approval: this | ||||
|       } | ||||
|     }, | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         currIndex: '0', | ||||
|         showList: true, | ||||
|         currentPage: "", | ||||
|         detail: {}, | ||||
|       } | ||||
|     }, | ||||
|     computed: { | ||||
|       tabs() { | ||||
|         return [ | ||||
|           { | ||||
|             label: "待我审批", name: "forMyApproval", value: "0", comp: forMyApproval, detail: approvalDetail, | ||||
|             permission: "" | ||||
|           }, | ||||
|           { | ||||
|             label: "我已审批", name: "forMyApproval", value: "1", comp: forMyApproval, detail: approvalDetail, | ||||
|             permission: "" | ||||
|           }, | ||||
|           { | ||||
|             label: "抄送我的", name: "forMyApproval", value: "3", comp: forMyApproval, detail: approvalDetail, | ||||
|             permission: "" | ||||
|           }, | ||||
|           { | ||||
|             label: "超时督办", name: "forMyApproval", value: "4", comp: forMyApproval, detail: approvalDetail, | ||||
|             permission: "" | ||||
|           }, | ||||
|         ] | ||||
|       }, | ||||
|       currentTab() { | ||||
|         return this.tabs[this.currIndex] || {} | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|       goPage(obj) { | ||||
|         this.currentPage = this.tabs[Number(this.currIndex)][obj.key]; | ||||
|         obj.row && (this.detail = obj.row) | ||||
|         this.showList = false; | ||||
|       }, | ||||
|       goBack() { | ||||
|         this.showList = true; | ||||
|         this.$nextTick(() => { | ||||
|           this.$refs[this.currIndex][0].getList(); | ||||
|         }) | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .approval-manage { | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background-color: #F3F6F9; | ||||
|   } | ||||
| </style> | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,218 @@ | ||||
| <template> | ||||
|   <div class="for-my-approval"> | ||||
|     <ai-list isTabs> | ||||
|       <template #content> | ||||
|         <ai-search-bar> | ||||
|           <template #right> | ||||
|             <el-input | ||||
|               v-model="search.param" | ||||
|               size="small" | ||||
|               placeholder="标题/发起人" | ||||
|               @keyup.enter.native="search.current = 1, getList()" | ||||
|               @clear="reset" | ||||
|               clearable | ||||
|               suffix-icon="iconfont iconSearch"/> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ul class="list-wrap"> | ||||
|           <li v-for="(item,index) in tableData" :key="index" @click="goTo('detail',item)"> | ||||
|             <div class="list-title">{{item.processDefName}}</div> | ||||
|             <div class="info"> | ||||
|               <div class="item"> | ||||
|                 <label>发起人:</label> | ||||
|                 <span>{{item.createUserName}}</span> | ||||
|               </div> | ||||
|               <div class="item"> | ||||
|                 <label>所属部门:</label> | ||||
|                 <span>{{dict.getLabel('hbDepartment',item.department)}}</span> | ||||
|               </div> | ||||
|               <div class="item"> | ||||
|                 <label>所属分类:</label> | ||||
|                 <span>{{item.classificationName}}</span> | ||||
|               </div> | ||||
|               <div class="item"> | ||||
|                 <label>发起时间:</label> | ||||
|                 <span>{{item.createTime|format}}</span> | ||||
|               </div> | ||||
|             </div> | ||||
|             <svgIcon :class-name="icon(item.approvalStatus)" class="svg"></svgIcon> | ||||
|           </li> | ||||
|         </ul> | ||||
|         <div class="no-data" v-if="tableData.length==0"></div> | ||||
|         <el-pagination class="pagination" background :current-page="search.current" @current-change="handleCurrent" | ||||
|                        layout="total,prev, pager, next,sizes, jumper" | ||||
|                        :total="total" | ||||
|                        @size-change="handleSizeChange" | ||||
|                        :page-size="search.size" | ||||
|                        :page-sizes="[10, 20, 50, 100,200]"> | ||||
|         </el-pagination> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import svgIcon from "./svgIcon"; | ||||
|   import day from 'dayjs' | ||||
|  | ||||
|   export default { | ||||
|     name: "forMyApproval", | ||||
|     components: {svgIcon}, | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function, | ||||
|       listType: String, | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           param:"", | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|         }, | ||||
|         tableData: [], | ||||
|         total: 0 | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|       icon(icon) { | ||||
|         if(icon==0){ | ||||
|           return "iconsp_ing" | ||||
|         }else if(icon==1){ | ||||
|           return "iconsp-pass" | ||||
|         }else if(icon==2){ | ||||
|           return "iconsp_refused" | ||||
|         } | ||||
|         return "iconcancel" | ||||
|       }, | ||||
|  | ||||
|       goTo(key = '', row) { | ||||
|         this.$emit('goPage', {key, row}); | ||||
|       }, | ||||
|  | ||||
|       reset() { | ||||
|         this.search.param = "" | ||||
|         this.search.current = 1 | ||||
|         this.search.size = 10 | ||||
|         this.getList() | ||||
|       }, | ||||
|  | ||||
|       handleCurrent(val) { | ||||
|         this.search.current = val; | ||||
|         this.getList(); | ||||
|       }, | ||||
|  | ||||
|       handleSizeChange(val) { | ||||
|         this.search.size = val; | ||||
|         this.getList(); | ||||
|       }, | ||||
|  | ||||
|       getList() { | ||||
|         this.instance.post(`/app/approv-alapply-info/list`,null,{ | ||||
|           params:{ | ||||
|             listType: this.listType, | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res && res.data) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     filters:{ | ||||
|       format(time){ | ||||
|         return time ? day(time).format('YYYY-MM-DD HH:mm') : '-' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created(){ | ||||
|       this.dict.load(['hbDepartment']).then(()=>{ | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .for-my-approval { | ||||
|     height: 100%; | ||||
|     background: #f3f6f9; | ||||
|     overflow: auto; | ||||
|  | ||||
|     .list-wrap { | ||||
|       width: 100%; | ||||
|       min-height: 100%; | ||||
|  | ||||
|       li { | ||||
|         width: 100%; | ||||
|         height: 80px; | ||||
|         border-radius: 4px; | ||||
|         border: 1px solid #D8E0E8; | ||||
|         margin-bottom: 8px; | ||||
|         box-sizing: border-box; | ||||
|         padding: 16px 32px; | ||||
|         user-select: none; | ||||
|         cursor: pointer; | ||||
|         position: relative; | ||||
|  | ||||
|         .list-title { | ||||
|           font-size: 16px; | ||||
|           font-weight: 600; | ||||
|           color: #333333; | ||||
|           padding-bottom: 6px; | ||||
|         } | ||||
|  | ||||
|         .info { | ||||
|           width: 90%; | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           justify-content: space-between; | ||||
|  | ||||
|           .item { | ||||
|             width: 30%; | ||||
|             & > label { | ||||
|               color: #666666; | ||||
|             } | ||||
|  | ||||
|             & > span { | ||||
|               color: #333333; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         .svg { | ||||
|           width: 66px; | ||||
|           height: 61px; | ||||
|           position: absolute; | ||||
|           right: 0; | ||||
|           bottom: 0; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .no-data { | ||||
|       background-size: 120px 120px; | ||||
|       height: 160px; | ||||
|       margin: 48px auto 10px; | ||||
|     } | ||||
|  | ||||
|     .pagination { | ||||
|       box-sizing: border-box; | ||||
|       padding: 24px 0 32px 0; | ||||
|     } | ||||
|  | ||||
|     .iconfont { | ||||
|       user-select: none; | ||||
|       cursor: pointer; | ||||
|     } | ||||
|  | ||||
|     ::v-deep .AiSearchBar { | ||||
|       margin-bottom: 16px; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
| @@ -0,0 +1,25 @@ | ||||
| <template> | ||||
|   <svg class="icon" aria-hidden="true" v-bind="$attrs"> | ||||
|     <use :xlink:href="iconName"></use> | ||||
|   </svg> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: "svgIcon", | ||||
|     props: { | ||||
|       className: { | ||||
|         type: String, | ||||
|       } | ||||
|     }, | ||||
|     computed: { | ||||
|       iconName() { | ||||
|         return `#${this.className}` | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|  | ||||
| </style> | ||||
| @@ -0,0 +1,186 @@ | ||||
| <template> | ||||
|   <section class="AppCorporateSeal"> | ||||
|       <ai-list v-if="showList"> | ||||
|         <template slot="title"> | ||||
|           <ai-title title="企业印章" :isShowBottomBorder="true"></ai-title> | ||||
|         </template> | ||||
|         <template slot="content"> | ||||
|           <div class="signaturePane"> | ||||
|             <div class="signatureCard" v-for="(op,i) in signatures" :key="i"> | ||||
|               <div class="default" v-if="op.isDefault==1">默认</div> | ||||
|               <div class="body"> | ||||
|                 <el-image :src="`data:image/png;base64,${op.signSealData}`"/> | ||||
|               </div> | ||||
|               <div class="footer"> | ||||
|                 <el-button type="text" :disabled="op.isDefault==1" @click.stop="handleSetDefault(op.id)">设为默认</el-button> | ||||
|                 <hr/> | ||||
|                 <el-button type="text" :disabled="op.isDefault==1||op.signType==1" @click.stop="handleDelete(op.id)">删除 | ||||
|                 </el-button> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="signatureCard add" @click="showList=false"> | ||||
|               <ai-icon icon="iconAdd" size="32px"/> | ||||
|               <span>点击添加印章</span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </template> | ||||
|       </ai-list> | ||||
|     <seal-detail v-else/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import SealDetail from "./sealDetail"; | ||||
|  | ||||
|   export default { | ||||
|     name: "AppCorporateSeal", | ||||
|     label: "企业印章", | ||||
|     components: {SealDetail}, | ||||
|     provide() { | ||||
|       return { | ||||
|         seal: this | ||||
|       } | ||||
|     }, | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         signatures: [], | ||||
|         showList: true | ||||
|       } | ||||
|     }, | ||||
|     created() { | ||||
|       this.getSignatures() | ||||
|     }, | ||||
|     methods: { | ||||
|       getSignatures() { | ||||
|         this.instance.post("/app/syssignaccount/list", null, { | ||||
|           params: { | ||||
|             signType: 2, | ||||
|             size: 999 | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.signatures = res.data.records | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       handleSetDefault(id) { | ||||
|         this.$confirm("是否设置该印章为默认印章?").then(() => { | ||||
|           this.instance.post("/app/syssignaccount/default", null, {params: {id, listType: 1}}).then(res => { | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("设置成功!") | ||||
|               this.getSignatures() | ||||
|             } | ||||
|           }).catch(() => 0) | ||||
|         }) | ||||
|       }, | ||||
|       handleDelete(ids) { | ||||
|         this.$confirm("是否删除该印章?").then(() => { | ||||
|           this.instance.post("/app/syssignaccount/delete", null, {params: {ids}}).then(res => { | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("删除成功!") | ||||
|               this.getSignatures() | ||||
|             } | ||||
|           }).catch(() => 0) | ||||
|         }) | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .AppCorporateSeal { | ||||
|     height: 100%; | ||||
|     background: #f3f6f9; | ||||
|  | ||||
|     ::v-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> | ||||
| @@ -0,0 +1,233 @@ | ||||
| <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> | ||||
| 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(this.idCardNoUtil.checkIdCardNo(v) ? undefined : "身份证号码格式有误")} | ||||
|         ], | ||||
|         agentIdNumber: [ | ||||
|           {required: true, message: "请填写代理人身份证号码"}, | ||||
|           {validator: (r, v, cb) => cb(this.idCardNoUtil.checkIdCardNo(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; | ||||
|  | ||||
|   ::v-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; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep .ai-detail__footer > .el-button { | ||||
|     width: 92px; | ||||
|     height: 32px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,204 @@ | ||||
| <template> | ||||
|   <section class="examination-approval"> | ||||
|     <ai-list v-if="!showList"> | ||||
|       <template #title> | ||||
|         <ai-title title="审批分类" :isShowBottomBorder="true" :instance="instance"></ai-title> | ||||
|       </template> | ||||
|       <template #content> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <el-button type="primary" icon="iconfont iconAdd" @click="showList = true">添加分类</el-button> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input | ||||
|               v-model="search.name" | ||||
|               size="small" | ||||
|               placeholder="分类名称/创建人" | ||||
|               @keyup.enter.native="search.current = 1, getList()" | ||||
|               @clear="reset" | ||||
|               clearable | ||||
|               suffix-icon="iconfont iconSearch"/> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table | ||||
|           :tableData="tableData" | ||||
|           :col-configs="colConfigs" | ||||
|           :total="total" | ||||
|           :header-cell-style="{fontWeight:'bold',color:'#333'}" | ||||
|           :current.sync="search.current" | ||||
|           :size.sync="search.size" | ||||
|           @getList="getList"> | ||||
|  | ||||
|           <el-table-column label="是否启用" slot="status" align="center" width="150"> | ||||
|             <template v-slot="{row}"> | ||||
|               <el-switch | ||||
|                 v-model="row.status" | ||||
|                 @change="onChange(row)" active-value="1" inactive-value="0" | ||||
|                 active-color="#5088FF" | ||||
|                 inactive-color="#D0D4DC"> | ||||
|               </el-switch> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|            | ||||
|           <el-table-column label="操作" slot="options" align="center" width="150"> | ||||
|             <template v-slot="{row}"> | ||||
|               <el-button type="text" title="修改" @click="editInfo(row)">修改</el-button> | ||||
|               <el-button type="text" title="删除" @click="deleteInfo(row)">删除</el-button> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <addClassification v-else @back="showList=false;row={},getList()" :instance="instance" | ||||
|                        :row="row"></addClassification> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
|   import addClassification from "./components/addClassification"; | ||||
|   import day from 'dayjs' | ||||
|  | ||||
|   export default { | ||||
|     name: "AppExaminationApproval", | ||||
|     label: "审批分类", | ||||
|     components: {addClassification}, | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           name: "", | ||||
|         }, | ||||
|         total: 0, | ||||
|         tableData: [], | ||||
|         row: {}, | ||||
|         showList: false | ||||
|       } | ||||
|     }, | ||||
|     computed: { | ||||
|       colConfigs() { | ||||
|         return [ | ||||
|           { | ||||
|             prop: 'name', | ||||
|             align: 'left', | ||||
|             label: '分类名称', | ||||
|           }, | ||||
|           { | ||||
|             prop: 'desc', | ||||
|             align: 'left', | ||||
|             label: '分类描述', | ||||
|           }, | ||||
|           { | ||||
|             prop: 'createUserName', | ||||
|             align: 'center', | ||||
|             label: '创建人', | ||||
|           }, | ||||
|           { | ||||
|             prop: 'createTime', | ||||
|             align: 'center', | ||||
|             label: '创建日期', | ||||
|           }, | ||||
|           { | ||||
|             prop: 'showIndex', | ||||
|             align: 'center', | ||||
|             label: '排序', | ||||
|           }, | ||||
|           { | ||||
|             slot: 'status', | ||||
|             align: 'center', | ||||
|             label: '是否启用', | ||||
|           }, | ||||
|           { | ||||
|             slot: 'options', | ||||
|             align: 'center', | ||||
|             label: '操作', | ||||
|           }, | ||||
|         ] | ||||
|       }, | ||||
|     }, | ||||
|     methods: { | ||||
|       /** | ||||
|        * 编辑 | ||||
|        * */ | ||||
|       editInfo(row) { | ||||
|         this.row = row | ||||
|         this.showList = true | ||||
|       }, | ||||
|  | ||||
|       /** | ||||
|        * 启用、停用 | ||||
|        */ | ||||
|       onChange(row) { | ||||
|         this.instance.post(`/app/zwspapprovalclassification/enable?id=${row.id}`).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$message.success(+row.status ? "已启用" : '不启用') | ||||
|             this.getList() | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       reset() { | ||||
|         this.search.name = "" | ||||
|         this.getList() | ||||
|       }, | ||||
|  | ||||
|       getList() { | ||||
|         this.instance.post(`/app/zwspapprovalclassification/list`, null, { | ||||
|           params: { | ||||
|             ...this.search, | ||||
|           }, | ||||
|         }).then(res => { | ||||
|           if (res && res.data) { | ||||
|             this.tableData = res.data.records.map(e => ({ | ||||
|               ...e, | ||||
|               createTime: day(e.createTime).format("YYYY-MM-DD"), | ||||
|             })); | ||||
|             this.total = res.data.total; | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       /** | ||||
|        * 删除 | ||||
|        */ | ||||
|       deleteInfo({id}) { | ||||
|         this.$confirm("是否删除?").then(() => { | ||||
|           this.instance.post(`/app/zwspapprovalclassification/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success("删除成功") | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|     }, | ||||
|  | ||||
|     mounted() { | ||||
|       this.getList() | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .examination-approval { | ||||
|     height: 100%; | ||||
|     background: #f3f6f9; | ||||
|     overflow: auto; | ||||
|  | ||||
|     .iconfont { | ||||
|       user-select: none; | ||||
|       cursor: pointer; | ||||
|     } | ||||
|  | ||||
|     ::v-deep .ai-table { | ||||
|       margin-top: 16px; | ||||
|     } | ||||
|  | ||||
|   } | ||||
| </style> | ||||
| @@ -0,0 +1,197 @@ | ||||
| <template> | ||||
|   <section class="add-classification"> | ||||
|     <ai-detail> | ||||
|       <ai-title slot="title" :title="pageTitle" isShowBack isShowBottomBorder @onBackClick="$emit('back')"/> | ||||
|       <template #content> | ||||
|         <ai-card title="基本信息"> | ||||
|           <template #content> | ||||
|             <el-form :model="form" :rules="rules" ref="addClassification" label-suffix=":" label-width="100px" | ||||
|                      size="small"> | ||||
|               <el-form-item label="分类名称" prop="name"> | ||||
|                 <el-input v-model.trim="form.name" size="small" clearable placeholder="如“社会保障”(限10个字)" :maxlength="10" | ||||
|                           show-word-limit/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="排序" prop="showIndex"> | ||||
|                 <el-input v-model.number="form.showIndex" size="small" clearable placeholder="请输入数字,数字越小排序越前"/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="分类描述" prop="desc"> | ||||
|                 <el-input v-model.trim="form.desc" type="textarea" size="small" clearable placeholder="限500个字" | ||||
|                           :maxlength="500" show-word-limit :rows="4"/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="分类图标" prop="icon" class="icon-form"> | ||||
|                 <el-upload ref="iconUploader" action="#" :auto-upload="false" :on-change="handleUploadIcon" :limit="1" | ||||
|                            :show-file-list="false"> | ||||
|                   <el-image v-if="!!form.icon" class="el-upload-list__item" :src="form.icon"> | ||||
|                     <i class="el-icon-picture-outline"/> | ||||
|                   </el-image> | ||||
|                   <div v-else class="el-upload--picture-card"><i class="el-icon-plus"/></div> | ||||
|                 </el-upload> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="是否启用" prop="status"> | ||||
|                 <el-radio v-model="form.status" label="1">是</el-radio> | ||||
|                 <el-radio v-model="form.status" label="0">否</el-radio> | ||||
|               </el-form-item> | ||||
|             </el-form> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|       </template> | ||||
|       <template #footer> | ||||
|         <el-button class="btn" @click="$emit('back')">取消</el-button> | ||||
|         <el-button class="btn" type="primary" @click="submit">提交</el-button> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
|   export default { | ||||
|     name: "addClassification", | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       row: Object, | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         form: { | ||||
|           id: "", | ||||
|           name: "", | ||||
|           showIndex: "", | ||||
|           desc: "", | ||||
|           icon: "", | ||||
|           status: "1" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     computed: { | ||||
|       pageTitle() { | ||||
|         return this.row?.id ? "编辑分类" : "添加分类" | ||||
|       }, | ||||
|       rules() { | ||||
|         return { | ||||
|           name: [{required: true, message: '请输入分类名称', trigger: 'blur'}], | ||||
|           showIndex: [ | ||||
|             {required: true, message: '请输入排序数字'}, | ||||
|             {min: 1, max: 999, type: "number", message: '排序只能输入1~999之间的整数'}, | ||||
|           ], | ||||
|           desc: [{required: true, message: '请填写描述', trigger: 'blur'}], | ||||
|           icon: [{required: true, message: '请选择分类图标', trigger: 'blur'}], | ||||
|           status: [{required: true, message: '请选择是否启用', trigger: 'change'}], | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|  | ||||
|       /** | ||||
|        * 提交 | ||||
|        */ | ||||
|       submit() { | ||||
|         this.$refs['addClassification'].validate(valid => { | ||||
|           if (valid) { | ||||
|             this.instance.post(`/app/zwspapprovalclassification/addOrUpdate`, { | ||||
|               ...this.form, | ||||
|               status: Number(this.form.status) | ||||
|             }).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success(this.row.id ? "编辑成功" : "添加成功") | ||||
|                 this.$emit('back') | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       /** | ||||
|        * 获取详情 | ||||
|        */ | ||||
|       getDetail() { | ||||
|         this.instance.post(`/app/zwspapprovalclassification/queryDetailById?id=${this.row.id}`).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.form = res.data | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       /** | ||||
|        * 上传图标 | ||||
|        */ | ||||
|       handleUploadIcon(file) { | ||||
|         let data = new FormData() | ||||
|         data.append("file", file.raw) | ||||
|         this.instance.post(`/admin/file/add`, data).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.form.icon = res.data?.[0].replace(/;.*/, '') | ||||
|           } | ||||
|           this.$refs.iconUploader?.clearFiles() | ||||
|         }).catch(() => this.$refs.iconUploader?.clearFiles()); | ||||
|       } | ||||
|     }, | ||||
|     created() { | ||||
|       if (this.row.id) { | ||||
|         this.getDetail() | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .add-classification { | ||||
|     height: 100%; | ||||
|  | ||||
|     .iconAudit { | ||||
|       font-size: 36px; | ||||
|       color: #3D94FB; | ||||
|     } | ||||
|  | ||||
|     .el-upload-list__item { | ||||
|       width: 80px; | ||||
|       height: 80px; | ||||
|     } | ||||
|  | ||||
|     .icon-form { | ||||
|       ::v-deep .el-form-item__content { | ||||
|         display: flex; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .select-icon { | ||||
|       width: 96px; | ||||
|       height: 28px; | ||||
|       line-height: 0; | ||||
|     } | ||||
|  | ||||
|     .iconfont { | ||||
|       margin-right: 8px; | ||||
|     } | ||||
|  | ||||
|     .icon-style { | ||||
|       display: flex; | ||||
|       flex-wrap: wrap; | ||||
|  | ||||
|       .icon:hover { | ||||
|         border-color: #5088FF; | ||||
|       } | ||||
|  | ||||
|       .icon_color { | ||||
|         border-color: #5088FF; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .icon { | ||||
|       width: 48px; | ||||
|       height: 48px; | ||||
|       border: 1px solid #ddd; | ||||
|       border-radius: 4px; | ||||
|       margin-right: 16px; | ||||
|       margin-bottom: 16px; | ||||
|       cursor: pointer; | ||||
|     } | ||||
|  | ||||
|     .btn { | ||||
|       width: 92px; | ||||
|       height: 32px; | ||||
|  | ||||
|       &:nth-child(2) { | ||||
|         margin-left: 24px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
| @@ -0,0 +1,101 @@ | ||||
| <template> | ||||
|   <section class="AppLeavingMessage"> | ||||
|     <ai-list v-if="!showDetail"> | ||||
|       <template slot="title"> | ||||
|         <ai-title title="群众留言" :isShowBottomBorder="false" :instance="instance" :isShowArea="true" v-model="areaId" @change="changeArea"></ai-title> | ||||
|       </template> | ||||
|       <template slot="tabs"> | ||||
|         <el-tabs v-model="activeName" @tab-click="handleClick" class="tabs-page"> | ||||
|           <el-tab-pane v-for="(item, index) in paneList" :key="index" :label="item.label" :name="item.name"> | ||||
|             <component :is="comp" ref="list" :instance="instance" :dict="dict" :activeName="activeName" @toDetail="toDetail" | ||||
|                        :areaId="areaId"></component> | ||||
|           </el-tab-pane> | ||||
|         </el-tabs> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <template v-if="showDetail"> | ||||
|       <message-detail :instance="instance" :dict="dict" :detailId="detailId" @back="showDetail=false"></message-detail> | ||||
|     </template> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import {mapState} from "vuex"; | ||||
|   import AlreadyList from "./components/alreadyList"; | ||||
|   import MessageDetail from "./components/messageDetail"; | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppMassesMessage', | ||||
|     label: "群众留言", | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function, | ||||
|       openim: Function | ||||
|     }, | ||||
|     components: {AlreadyList, MessageDetail}, | ||||
|     data() { | ||||
|       return { | ||||
|         activeName: '0', | ||||
|         comp:"AlreadyList", | ||||
|         paneList: [ | ||||
|           { | ||||
|             label: '待我回复', | ||||
|             name: '0' | ||||
|           }, | ||||
|           { | ||||
|             label: '我已回复', | ||||
|             name: '1' | ||||
|           }, | ||||
|           { | ||||
|             label: '处理完成', | ||||
|             name: '2' | ||||
|           } | ||||
|         ], | ||||
|         showDetail: false, | ||||
|         detailId: '', | ||||
|         oldActiveName: '', | ||||
|         areaId: '', | ||||
|         hideLevel: '' | ||||
|       } | ||||
|     }, | ||||
|     computed: { | ||||
|       ...mapState(['user']) | ||||
|     }, | ||||
|     created() { | ||||
|       this.areaId = this.user.info.areaId | ||||
|       this.hideLevel = this.user.info.areaList.length | ||||
|     }, | ||||
|     methods: { | ||||
|       changeArea() { | ||||
|         this.$nextTick(() => { | ||||
|           this.$refs.list.getAppLeaveMessage() | ||||
|         }) | ||||
|       }, | ||||
|       openIM() { | ||||
|         if (this.openim) this.openim() | ||||
|       }, | ||||
|       handleClick(tab) { | ||||
|         if (this.oldActiveName == this.activeName) { | ||||
|           return | ||||
|         } | ||||
|         this.activeName = tab.name | ||||
|         this.$nextTick(() => { | ||||
|           this.$refs.list[0].getAppLeaveMessage() | ||||
|           this.$refs.list.search = {} | ||||
|           this.oldActiveName = tab.name | ||||
|         }) | ||||
|       }, | ||||
|       toDetail(id) { | ||||
|         this.detailId = id | ||||
|         this.showDetail = true | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
|   .AppLeavingMessage { | ||||
|     height: 100%; | ||||
|     background-color: #f3f6f9; | ||||
|   } | ||||
| </style> | ||||
| @@ -0,0 +1,273 @@ | ||||
| <template> | ||||
|   <section class="already-list"> | ||||
|     <ai-list isTabs> | ||||
|       <template #content> | ||||
|         <ai-search-bar bottomBorder> | ||||
|           <template #right> | ||||
|             <el-input size="small" v-model="search.title" placeholder="标题/编号" | ||||
|                       @keyup.enter.native="page.current=1,getAppLeaveMessage()" | ||||
|                       prefix-icon="iconfont iconSearch" clearable></el-input> | ||||
|             <el-button size="mini" type="primary" icon="iconfont iconSearch" style="margin-left:5px;" | ||||
|                        @click="page.current=1,getAppLeaveMessage()">查询 | ||||
|             </el-button> | ||||
|             <el-button size="mini" icon="el-icon-refresh-right" style="margin-left:5px;" @click="resetSearch"> | ||||
|               重置 | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table  :tableData="tableData" | ||||
|                    :col-configs="colConfigs" | ||||
|                    :total="total" | ||||
|                    ref="aitableex" | ||||
|                    :current.sync="search.current" | ||||
|                    :size.sync="search.size" | ||||
|                    @getList="getAppLeaveMessage"> | ||||
|           <el-table-column label="是否公示" slot="isPublic" align="center" width="150"> | ||||
|             <template v-slot="{row}"> | ||||
|               <el-switch v-model="row.isPublic" @change="onChange(row)" active-value="0" inactive-value="1" | ||||
|                          active-color="#D0D4DC" inactive-color="#5088FF"/> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|  | ||||
|           <el-table-column label="操作" slot="options" align="center" width="150"> | ||||
|             <template v-slot="{row}"> | ||||
|               <el-button type="text" title="详情" @click="toDetail(row.id)" v-if="$permissions('app_appleavemessagereply_detail')">详情</el-button> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|  | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
| import day from 'dayjs' | ||||
|  | ||||
| export default { | ||||
|   name: "alreadyList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|     activeName: String, | ||||
|     areaId: String | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       tableData: [], | ||||
|       columns: [ | ||||
|         { | ||||
|           label: '留言编号', | ||||
|           prop: 'msgCode', | ||||
|           type: '', | ||||
|           dict: '' | ||||
|         }, | ||||
|         { | ||||
|           label: '留言类型', | ||||
|           prop: 'type', | ||||
|           type: 'select', | ||||
|           dict: 'leaveMessageType' | ||||
|         }, | ||||
|         { | ||||
|           label: '标题', | ||||
|           prop: 'title', | ||||
|           type: '', | ||||
|           dict: '' | ||||
|         }, | ||||
|         { | ||||
|           label: '留言人', | ||||
|           prop: 'leaveName', | ||||
|           type: '', | ||||
|           dict: '' | ||||
|         }, | ||||
|         { | ||||
|           label: '创建时间', | ||||
|           prop: 'createTime', | ||||
|           type: 'time', | ||||
|           dict: '' | ||||
|         }, | ||||
|         { | ||||
|           label: '最后回复时间', | ||||
|           prop: 'lastReplyTime', | ||||
|           type: 'time', | ||||
|           dict: '' | ||||
|         }, | ||||
|         { | ||||
|           label: '处理状态0、待回复1、已回复', | ||||
|           prop: 'status', | ||||
|           type: '', | ||||
|           dict: '' | ||||
|         }, | ||||
|         { | ||||
|           label: '操作', | ||||
|           prop: 'operate', | ||||
|           type: '', | ||||
|           dict: '' | ||||
|         }, | ||||
|       ], | ||||
|       search: { | ||||
|         style: {}, | ||||
|         title: "" | ||||
|       }, | ||||
|       page: { | ||||
|         current: 1, | ||||
|         size: 10, | ||||
|       }, | ||||
|       total: 0, | ||||
|       detailId: '', | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     onChange({id, isPublic}) { | ||||
|       this.instance.post(`/app/appleavemessage/public?id=${id}`).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           console.log(isPublic) | ||||
|           this.$message.success(isPublic == 1 ? "已公示" : "不公示") | ||||
|           this.getAppLeaveMessage() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     navClick(item) { | ||||
|       this.navStatus = item.status | ||||
|     }, | ||||
|     isPermit(params) { | ||||
|       return this.permissions ? this.permissions(params) : false | ||||
|     }, | ||||
|     resetSearch() { | ||||
|       this.page.current = 1 | ||||
|       this.page.size = 10 | ||||
|       this.columns.map(c => { | ||||
|         if (c.type) this.search[c.prop] = null | ||||
|       }) | ||||
|       Object.keys(this.search).forEach((e) => { | ||||
|         this.search[e] = null; | ||||
|       }) | ||||
|       this.getAppLeaveMessage() | ||||
|     }, | ||||
|     handleCurrentChange(val) { | ||||
|       this.page.current = val | ||||
|       this.getAppLeaveMessage() | ||||
|     }, | ||||
|     handleSizeChange(val) { | ||||
|       this.page.size = val; | ||||
|       this.getAppLeaveMessage(); | ||||
|     }, | ||||
|     getAppLeaveMessage() { | ||||
|       this.search.status = this.activeName | ||||
|       this.search.areaId = this.user.info.areaId | ||||
|       this.instance.post("/app/appleavemessage/list", null, { | ||||
|         params: { | ||||
|           ...this.search, | ||||
|           ...this.page, | ||||
|           areaId: this.areaId | ||||
|         } | ||||
|       }).then(res => { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|       ) | ||||
|     }, | ||||
|  | ||||
|     addOrUpdateAppLeaveMessage() { | ||||
|       this.instance.post("/app/appleavemessage/addOrUpdate", this.dialog.add).then(() => { | ||||
|             this.getAppLeaveMessage() | ||||
|             this.$message.success("添加或修改成功!") | ||||
|           } | ||||
|       ) | ||||
|     }, | ||||
|     deleteAppLeaveMessage(ids) { | ||||
|       this.$confirm("是否要删除这些账号?", { | ||||
|         type: 'warning' | ||||
|       }).then(() => { | ||||
|         this.instance.post("/app/appleavemessage/delete", null, { | ||||
|           params: { | ||||
|             ids: ids | ||||
|           } | ||||
|         }).then(() => { | ||||
|               this.getAppLeaveMessage() | ||||
|               this.$message.success("删除成功!") | ||||
|             } | ||||
|         ) | ||||
|       }).catch(() => { | ||||
|           } | ||||
|       ) | ||||
|     }, | ||||
|     toDetail(id) { | ||||
|       this.$emit('toDetail', id) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   filters: { | ||||
|     format(time) { | ||||
|       return time ? day(time).format("YYYY-MM-DD HH:mm") : '-' | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   mounted() { | ||||
|     if (this.dict) this.dict.load(this.columns.map(e => e.type == 'select' ? e.dict : '')) | ||||
|     this.resetSearch() | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         { prop: 'msgCode',  label: '编号', align: 'center' }, | ||||
|         { prop: 'title',  label: '标题', align: 'center' }, | ||||
|         { prop: 'type',  label: '类型', align: 'center', | ||||
|           render:(h,{row})=>[<span>{this.dict.getLabel('leaveMessageType', row.type)}</span>] }, | ||||
|         { prop: 'leaveName',  label: '留言人', align: 'center' }, | ||||
|         { prop: 'createTime',  label: '留言提交时间', align: 'center' }, | ||||
|         { prop: 'lastReplyTime',  label: '最后回复时间', align: 'center' }, | ||||
|         { slot: 'isPublic'}, | ||||
|         { slot: 'options'}, | ||||
|       ] | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .already-list { | ||||
|   background-color: #f3f6f9; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   overflow: hidden; | ||||
|  | ||||
|   .el-table::before { | ||||
|     background-color: #fff !important; | ||||
|   } | ||||
|  | ||||
|   .header { | ||||
|     padding: 0 16px; | ||||
|     width: 100%; | ||||
|     background-color: #ffffff; | ||||
|     height: 48px; | ||||
|     line-height: 48px; | ||||
|     box-shadow: inset 0px -1px 0px 0px #d8dce3; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   .main-content { | ||||
|     box-sizing: border-box; | ||||
|     margin: 16px; | ||||
|     height: calc(100% - 80px); | ||||
|     background-color: white; | ||||
|     border: 1px solid #eee; | ||||
|     padding: 12px 16px; | ||||
|  | ||||
|     .searchBar { | ||||
|  | ||||
|       .el-col { | ||||
|         margin-bottom: 12px; | ||||
|       } | ||||
|  | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -0,0 +1,461 @@ | ||||
| <template> | ||||
|   <div class="message-detail iconPhoto-content"> | ||||
|     <ai-detail> | ||||
|       <ai-title slot="title" :title="titleText" isShowBack isShowBottomBorder @onBackClick="$emit('back')"></ai-title> | ||||
|       <template #rightBtn> | ||||
|         <p class="resident_top_area" style="text-align: right;" v-if="data.status != '2' && $permissions('app_appleavemessagereply_edit')"> | ||||
|           <el-button type="primary" class="el-icon-edit" v-if="data.status == '0'" @click="maskShow = true" style="width:104px">回复留言</el-button> | ||||
|           <el-button class="el-icon-switch-button del-btn-list" @click="close()" style="width:104px">关闭留言</el-button> | ||||
|         </p> | ||||
|       </template> | ||||
|  | ||||
|       <template #content> | ||||
|         <ai-card :title="data.title"> | ||||
|           <template #content> | ||||
|             <div class="content-main"> | ||||
|               <div class="main-header mar-b16"> | ||||
|                 <h6 style="font-weight:600;">{{ data.title }}</h6> | ||||
|                 <div class="time"> | ||||
|                   <span class="time-label" style="width: 243px;" | ||||
|                     >留言编号:<span style="color:#333">{{ data.msgCode }}</span></span | ||||
|                   > | ||||
|                   <span class="time-label" | ||||
|                     >留言时间:<span style="color:#333">{{ data.createTime }}</span></span | ||||
|                   > | ||||
|                   <span class="time-label" style="width: 258px;text-align: right" | ||||
|                     >留言人:<span style="color:#333">{{ data.leaveName }}  {{ data.leavePhone }}</span></span | ||||
|                   > | ||||
|                   <svg class="status-icon" aria-hidden="true"> | ||||
|                     <use xlink:href="#iconno_response" v-if="data.status == '0'"></use> | ||||
|                     <use xlink:href="#iconreplied" v-if="data.status == '1'"></use> | ||||
|                     <use xlink:href="#iconfinished" v-if="data.status == '2'"></use> | ||||
|                   </svg> | ||||
|                 </div> | ||||
|                 <p class="message-text border-t" style="padding: 16px">{{ data.content }}</p> | ||||
|                 <div v-if="data.images.length"> | ||||
|                   <div class="content-img" v-viewer> | ||||
|                     <img v-for="(item, index) in data.images" :src="item.accessUrl" alt="" :key="index" /> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <div class="main-list"> | ||||
|                 <div class="main-header mar-b16"> | ||||
|                   <h6 style="font-weight:600;">沟通记录</h6> | ||||
|                 </div> | ||||
|                 <div v-for="(item, index) in data.appLeaveMessageReplyList" :key="index" :class="item.headPortrait == null ? 'message-for reply' : 'message-for'" v-if="data.appLeaveMessageReplyList.length > 0"> | ||||
|                   <div class="message-title"> | ||||
|                     <img :src="item.headPortrait" alt="" class="user-img" v-if="item.headPortrait" /> | ||||
|                     <span class="iconfont iconProfile_Picture" v-else></span> | ||||
|                     <span class="user-name" v-if="!item.headPortrait"> | ||||
|                       <span style="color:#5088FF">{{ item.createUnitName }}  <span style="color:#333"> 回复</span></span | ||||
|                       ><br /> | ||||
|                       <span style="color:#999;font-size:12px">操作员:{{ item.createUserName }}{{ item.createUserPhone }}</span> | ||||
|                     </span> | ||||
|                     <span class="user-name" v-else>{{ item.createUserName }}</span> | ||||
|  | ||||
|                     <span style="color:#999;vertical-align: text-bottom">{{ item.createTime }}</span> | ||||
|                   </div> | ||||
|                   <p class="message-text">{{ item.content }}</p> | ||||
|                   <div v-if="item.images.length"> | ||||
|                     <div class="message-img-list" v-viewer> | ||||
|                       <img class="message-img" v-for="(items, index) in item.images" :src="items.accessUrl" :key="index" v-if="items.accessUrl" /> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div v-if="data.appLeaveMessageReplyList.length == 0" style="width:100%;text-align:center;color:#999;font-size:14px">暂无沟通记录</div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|     <ai-dialog :title="maskText" :visible.sync="maskShow" @onConfirm="confirm('ruleForm')" @onCancel="hideMask" :before-close="hideMask" width="720px"> | ||||
|       <el-form :rules="rules" ref="ruleForm" :model="ruleForm" label-width="auto"> | ||||
|         <el-form-item label="回复内容:" prop="content"> | ||||
|           <el-input type="textarea" v-model.trim="ruleForm.content" :row="4" show-word-limit :maxlength="1000" placeholder="请输入回复内容"></el-input> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="图片附件:" class="user"> | ||||
|           <span class="upload-more left-84">(最多9张)</span> | ||||
|           <el-upload class="upload-demo upload-list-small" ref="upload" multiple action list-type="picture-card" :file-list="images" :http-request="uploadFile" :on-remove="handleRemove" :on-change="handleChange" accept="jpeg/jpg/png"> | ||||
|             <div class="upload-img-small"> | ||||
|               <span class="iconfont iconPhoto iconPhoto2"></span> | ||||
|               <div class="upload-text">上传照片</div> | ||||
|             </div> | ||||
|           </el-upload> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import { mapState } from 'vuex' | ||||
| // import 'viewerjs/dist/viewer.css' | ||||
| import Viewer from 'v-viewer' | ||||
| import Vue from 'vue' | ||||
| Vue.use(Viewer) | ||||
|  | ||||
| export default { | ||||
|   name: 'messageDetail', | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|     detailId: String, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       titleText: '留言详情', | ||||
|       maskShow: false, | ||||
|       maskText: '回复留言', | ||||
|       images: [], | ||||
|       data: { | ||||
|         appLeaveMessageReplyList: [], | ||||
|       }, | ||||
|       rules: { | ||||
|         content: [{ required: true, message: '请输入回复内容', trigger: 'blur' }], | ||||
|       }, | ||||
|       ruleForm: { | ||||
|         content: '', | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|   }, | ||||
|   created() {}, | ||||
|   mounted() { | ||||
|     console.log(this.user) | ||||
|     this.getDetailInfo() | ||||
|   }, | ||||
|   methods: { | ||||
|     getDetailInfo() { | ||||
|       this.data.appLeaveMessageReplyList = [] | ||||
|       this.instance.post(`app/appleavemessage/queryDetailById?id=` + this.detailId).then((res) => { | ||||
|         this.data = res.data | ||||
|         this.data.images = JSON.parse(res.data.images) | ||||
|         if (this.data.appLeaveMessageReplyList.length) { | ||||
|           this.data.appLeaveMessageReplyList.map((item) => { | ||||
|             if (item.images) { | ||||
|               item.images = JSON.parse(item.images || '[]') | ||||
|             } | ||||
|             return item | ||||
|           }) | ||||
|         } | ||||
|         this.data.appLeaveMessageReplyList.reverse() | ||||
|       }) | ||||
|     }, | ||||
|     confirm(formName) { | ||||
|       this.$refs[formName].validate((valid) => { | ||||
|         if (valid) { | ||||
|           this.confirmFn() | ||||
|         } else { | ||||
|           return false | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     confirmFn() { | ||||
|       let images = [] | ||||
|       this.images.map((item) => { | ||||
|         images.push({ fileId: item.fileId, accessUrl: item.accessUrl }) | ||||
|       }) | ||||
|       let params = { | ||||
|         content: this.ruleForm.content, | ||||
|         images: JSON.stringify(images), | ||||
|         msgCode: this.data.msgCode, | ||||
|         userType: '1', | ||||
|         createUnitId: this.user.info.unitId, | ||||
|         createUnitName: this.user.info.unitName, | ||||
|       } | ||||
|       this.instance.post(`app/appleavemessagereply/addOrUpdate`, params).then((res) => { | ||||
|         console.log(res) | ||||
|         this.maskShow = false | ||||
|         this.getDetailInfo() | ||||
|       }) | ||||
|     }, | ||||
|     hideMask() { | ||||
|       this.maskShow = false | ||||
|       this.images = [] | ||||
|       this.$nextTick(() => { | ||||
|         this.$refs.ruleForm.resetFields() | ||||
|       }) | ||||
|     }, | ||||
|     close() { | ||||
|       this.$confirm('关闭留言之后,双方都将无法再进行回复,是否确定关闭本次留言?', { | ||||
|         type: 'warning', | ||||
|       }) | ||||
|         .then(() => { | ||||
|           let params = this.data | ||||
|           params.status = '2' | ||||
|           params.images = JSON.stringify(params.images) | ||||
|           if (params.appLeaveMessageReplyList.length) { | ||||
|             params.appLeaveMessageReplyList.map((item) => { | ||||
|               item.images = JSON.stringify(item.images) | ||||
|               return item | ||||
|             }) | ||||
|           } | ||||
|           this.instance.post(`app/appleavemessage/addOrUpdate`, params).then((res) => { | ||||
|             this.getDetailInfo() | ||||
|           }) | ||||
|         }) | ||||
|         .catch(() => {}) | ||||
|     }, | ||||
|     // 上传照片 | ||||
|     uploadFile(file) { | ||||
|       console.log(this.images.length > 9) | ||||
|       if (this.images.length > 9) { | ||||
|         this.$message.warning('上传图片不能超过9张') | ||||
|         this.images.map((item, index) => { | ||||
|           if (item.uid == file.file.uid) { | ||||
|             this.images.splice(index, 1) | ||||
|           } | ||||
|           return this.images | ||||
|         }) | ||||
|       } | ||||
|       const isLt2M = file.file.size / 1024 / 1024 < 2 | ||||
|       if (!isLt2M) { | ||||
|         this.$message.warning('图片大小不能超过 2MB!') | ||||
|         return | ||||
|       } | ||||
|       let formData = new FormData() | ||||
|       formData.append('file', file.file) | ||||
|       let file2 = formData | ||||
|       this.instance.post(`/admin/file/add`, file2, { withCredentials: false }).then((res) => { | ||||
|         if (res.code == 0) { | ||||
|           let imgInfo = res.data[0].split(';') | ||||
|           let img = { | ||||
|             fileId: imgInfo[1], | ||||
|             accessUrl: imgInfo[0], | ||||
|           } | ||||
|           this.images.map((item, index) => { | ||||
|             if (item.uid == file.file.uid) { | ||||
|               this.images[index].fileId = img.fileId | ||||
|               this.images[index].accessUrl = img.accessUrl | ||||
|               this.images[index].url = img.accessUrl | ||||
|             } | ||||
|             return this.images | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleChange(file, fileList) { | ||||
|       this.images = fileList | ||||
|     }, | ||||
|     handleRemove(file, fileList) { | ||||
|       this.images = fileList | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .message-detail { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   overflow: auto; | ||||
|   position: relative; | ||||
|   background-color: #f3f6f9; | ||||
|   .left-84 { | ||||
|     left: -84px; | ||||
|   } | ||||
|   .iconProfile_Picture { | ||||
|     font-size: 40px; | ||||
|   } | ||||
|  | ||||
|   .iconBack_Large { | ||||
|     width: 16px; | ||||
|     height: 16px; | ||||
|     color: #2266ff; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|   .content { | ||||
|     padding-top: 24px; | ||||
|     width: 100%; | ||||
|     height: calc(100% - 80px); | ||||
|     overflow-y: scroll; | ||||
|     .content-main { | ||||
|       width: 760px; | ||||
|       margin: 0 auto; | ||||
|       .main-header { | ||||
|         width: 100%; | ||||
|         box-sizing: border-box; | ||||
|         background-color: #fff; | ||||
|         border: 1px solid #eee; | ||||
|         h6 { | ||||
|           font-size: 16px; | ||||
|           color: #333; | ||||
|           padding: 0 16px; | ||||
|           min-height: 54px; | ||||
|           line-height: 54px; | ||||
|           box-sizing: border-box; | ||||
|         } | ||||
|         .time { | ||||
|           height: 54px; | ||||
|           line-height: 54px; | ||||
|           font-size: 12px; | ||||
|           padding: 0 16px; | ||||
|           box-sizing: border-box; | ||||
|           position: relative; | ||||
|           overflow: hidden; | ||||
|           .time-label { | ||||
|             color: #999; | ||||
|             display: inline-block; | ||||
|           } | ||||
|         } | ||||
|         .status-icon { | ||||
|           position: absolute; | ||||
|           width: 66px; | ||||
|           height: 66px; | ||||
|           top: -5px; | ||||
|           right: 0; | ||||
|         } | ||||
|       } | ||||
|       .main-list { | ||||
|         background-color: #fff; | ||||
|         padding-bottom: 80px; | ||||
|         .message-for { | ||||
|           width: 728px; | ||||
|           margin: 0 auto 24px auto; | ||||
|           padding: 16px 16px 8px; | ||||
|           box-sizing: border-box; | ||||
|           font-size: 14px; | ||||
|           .message-title { | ||||
|             height: 40px; | ||||
|             line-height: 40px; | ||||
|             margin-bottom: 6px; | ||||
|             .user-img { | ||||
|               display: inline-block; | ||||
|               width: 40px; | ||||
|               height: 40px; | ||||
|               border-radius: 50%; | ||||
|               background-color: red; | ||||
|             } | ||||
|             .user-name { | ||||
|               display: inline-block; | ||||
|               width: 510px; | ||||
|               color: #333; | ||||
|               vertical-align: text-bottom; | ||||
|               padding-left: 8px; | ||||
|               box-sizing: border-box; | ||||
|             } | ||||
|           } | ||||
|           .message-text { | ||||
|             padding-left: 48px; | ||||
|             color: #666; | ||||
|             margin-bottom: 16px; | ||||
|           } | ||||
|           .message-img-list { | ||||
|             padding-left: 48px; | ||||
|             .message-img { | ||||
|               display: inline-block; | ||||
|               width: 113px; | ||||
|               height: 113px; | ||||
|               margin: 0 16px 16px 0; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|         .reply { | ||||
|           background-color: #f5f6f7; | ||||
|           .message-title { | ||||
|             .user-name { | ||||
|               line-height: 20px; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .content-img { | ||||
|     padding: 0 16px; | ||||
|     img { | ||||
|       width: 84px; | ||||
|       height: 84px; | ||||
|       margin: 0 16px 16px 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .operation-foot { | ||||
|     overflow: hidden; | ||||
|     //   position: absolute; | ||||
|     bottom: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 64px; | ||||
|     line-height: 64px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     background-color: #f3f6f9; | ||||
|     box-shadow: inset 0px 1px 0px 0px #eeeeee; | ||||
|     button { | ||||
|       width: 92px; | ||||
|       height: 32px; | ||||
|       padding: 0 !important; | ||||
|     } | ||||
|     .delete-btn { | ||||
|       background-color: #fff; | ||||
|     } | ||||
|   } | ||||
|   .mask { | ||||
|     overflow: hidden; | ||||
|     .el-form-item__content { | ||||
|       float: left; | ||||
|       width: calc(100% - 100px) p { | ||||
|         font-size: 14px; | ||||
|         color: #222222; | ||||
|       } | ||||
|     } | ||||
|     .el-form-item__label { | ||||
|       display: inline-block; | ||||
|       width: 130px; | ||||
|       text-align: right; | ||||
|       font-size: 14px; | ||||
|       float: left; | ||||
|     } | ||||
|     .operation { | ||||
|       overflow: hidden; | ||||
|       //   position: absolute; | ||||
|       bottom: 0; | ||||
|       left: 0; | ||||
|       width: 100%; | ||||
|       height: 64px; | ||||
|       line-height: 64px; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       background-color: #f3f6f9; | ||||
|       box-shadow: inset 0px 1px 0px 0px #eeeeee; | ||||
|     } | ||||
|   } | ||||
|   .status { | ||||
|     span { | ||||
|       display: inline-block; | ||||
|       width: 24px; | ||||
|       height: 24px; | ||||
|       line-height: 24px; | ||||
|       text-align: center; | ||||
|     } | ||||
|   } | ||||
|   .status0 { | ||||
|     background-color: #eff6ff; | ||||
|     color: #2266ff; | ||||
|   } | ||||
|   .status1 { | ||||
|     background-color: #e8ecff; | ||||
|     color: #2244ff; | ||||
|   } | ||||
|   .status2 { | ||||
|     background-color: #fff3e8; | ||||
|     color: #ff8822; | ||||
|   } | ||||
|   .status3 { | ||||
|     background-color: #eaf5e8; | ||||
|     color: #2ea222; | ||||
|   } | ||||
|   .icon { | ||||
|     display: inline-block; | ||||
|     width: 32px; | ||||
|     height: 32px; | ||||
|     margin-top: 16px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,82 @@ | ||||
| <template> | ||||
|   <section class="matters-config"> | ||||
|     <ai-list v-if="!showDetail"> | ||||
|       <template #title> | ||||
|         <ai-title title="事项配置" :isShowBottomBorder="false"></ai-title> | ||||
|       </template> | ||||
|       <template slot="tabs"> | ||||
|         <el-tabs class="tabs-page" v-model="currIndex"> | ||||
|           <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" :tab="currentTab"/> | ||||
|           </el-tab-pane> | ||||
|         </el-tabs> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <component v-else :is="currentComp" :instance="instance" :dict="dict" | ||||
|                :processType="currentTab.value" :row="row"></component> | ||||
|  | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import addConfig from './components/addConfig' | ||||
| import configList from "./components/configList"; | ||||
| import guidance from "./components/guidance"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppMattersConfig", | ||||
|   label: '事项配置', | ||||
|   components: {addConfig,guidance}, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       currIndex: "0", | ||||
|       row: {}, | ||||
|       currentComp: "", | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     tabs() { | ||||
|       return [ | ||||
|         {label: "网上办事", name: "configList", value: "0", comp: configList, detail: addConfig, permission: ""}, | ||||
|         {label: "办事指南", name: "configList", value: "2", comp: configList, detail: guidance, permission: ""}, | ||||
|       ] | ||||
|     }, | ||||
|     currentTab() { | ||||
|       return this.tabs?.[this.currIndex] || {} | ||||
|     }, | ||||
|     showDetail() { | ||||
|       return !!this.$route.query?.id || !!this.$route.query?.processType | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     goPage(params) { | ||||
|       this.row = params.row | ||||
|       this.currentComp = params.comp | ||||
|       this.$router.push({query: {processType: this.currentTab.value}}) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.$router.push({query: {}}); | ||||
|     this.$dict.load("hbDepartment", 'sex', 'nation', 'marital', 'native_place', 'education', 'candidateApproverType', 'scopeCandidates', 'nodeType') | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .matters-config { | ||||
|   height: 100%; | ||||
|   background: #f3f6f9; | ||||
|   overflow: auto; | ||||
|  | ||||
|   .iconfont { | ||||
|     user-select: none; | ||||
|     cursor: pointer; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,252 @@ | ||||
| <template> | ||||
|   <div class="add-config" :class="[activeStep == 1 ? 'formLayout' : '']"> | ||||
|     <ai-detail> | ||||
|       <ai-title slot="title" :title="detailTitle" isShowBack isShowBottomBorder @onBackClick="handleBack"/> | ||||
|       <template slot="step"> | ||||
|         <div class="step"> | ||||
|           <el-steps :active="activeStep" simple> | ||||
|             <el-step v-for="(step,i) in processList" :key="i" v-bind="step" :icon="getStepIcon(i)"/> | ||||
|           </el-steps> | ||||
|         </div> | ||||
|       </template> | ||||
|       <template #content v-if="refresh"> | ||||
|         <baseInfo ref="baseInfo" :instance="instance" :dict="dict" v-show="activeStep==0"/> | ||||
|         <applyForm ref="applyForm" :value="filedList" :instance="instance" :dict="dict" v-show="activeStep==1"/> | ||||
|         <attachmentMaterial ref="attachmentMaterial" :instance="instance" v-show="activeStep==2"/> | ||||
|         <processApproval ref="processApproval" :approvalSteps="applyForm.approvalSteps" :instance="instance" | ||||
|                          :dict="dict" v-show="activeStep==3"/> | ||||
|       </template> | ||||
|       <template #footer> | ||||
|         <el-button class="btn" v-if="activeStep==0" @click="handleBack">取消</el-button> | ||||
|         <el-button class="btn" v-else @click="preStep">上一步</el-button> | ||||
|         <el-button class="btn" type="primary" v-if="[0,1,2].includes(activeStep)" @click="nextStep">下一步</el-button> | ||||
|         <el-button class="btn" type="primary" v-if="activeStep==3" @click="save">保存</el-button> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {applyForm, attachmentMaterial, baseInfo, processApproval} from './index' | ||||
|  | ||||
| export default { | ||||
|   name: "addConfig", | ||||
|   provide() { | ||||
|     return { | ||||
|       config: this | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     row: Object, | ||||
|     processType: String | ||||
|   }, | ||||
|   components: {baseInfo, applyForm, attachmentMaterial, processApproval}, | ||||
|   data() { | ||||
|     return { | ||||
|       activeStep: 0, | ||||
|       baseInfo: {}, | ||||
|       applyForm: { | ||||
|         tableId: "", | ||||
|         approvalSteps: "", | ||||
|       }, | ||||
|       processAnnexDefs: [], | ||||
|       detailObj: { | ||||
|         tableInfo: {} | ||||
|       }, | ||||
|       refresh: true, | ||||
|       filedList: [], | ||||
|       tableFieldInfos: [] | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     processList() { | ||||
|       return [ | ||||
|         {title: '基本信息', activeIndex: 0}, | ||||
|         {title: '申请表单', activeIndex: 1}, | ||||
|         {title: '附件材料', activeIndex: 2}, | ||||
|         {title: '审批流程', activeIndex: 3} | ||||
|       ] | ||||
|     }, | ||||
|     detailTitle() { | ||||
|       return this.detailObj?.id ? "编辑事项" : "添加事项" | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     /** | ||||
|      * 上一步 | ||||
|      * */ | ||||
|     preStep() { | ||||
|       this.activeStep-- | ||||
|     }, | ||||
|     /** | ||||
|      * 下一步 | ||||
|      */ | ||||
|     nextStep() { | ||||
|       switch (this.activeStep) { | ||||
|         case 0: | ||||
|           this.handleBaseInfo() | ||||
|           break | ||||
|         case 1: | ||||
|           this.$refs['applyForm'].onConfirm().then(res => { | ||||
|             if (!res.length) { | ||||
|               return this.$message.error('表单配置不能为空') | ||||
|             } | ||||
|             this.tableFieldInfos = res | ||||
|             this.activeStep++ | ||||
|           }) | ||||
|           break | ||||
|         case 2: | ||||
|           this.$refs['attachmentMaterial'].handleAttachmentMaterial().then(res => { | ||||
|             this.annexs = res | ||||
|             this.activeStep++ | ||||
|           }).catch(err => { | ||||
|             console.error(err); | ||||
|           }) | ||||
|           break | ||||
|       } | ||||
|     }, | ||||
|     handleBaseInfo() { | ||||
|       this.$refs['baseInfo'].banseInfoForm().then(res => { | ||||
|         if (res) { | ||||
|           // this.$refs['applyForm'].getFormList() | ||||
|           this.baseInfo = res | ||||
|           this.activeStep++ | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     /** | ||||
|      * 保存 | ||||
|      */ | ||||
|     save() { | ||||
|       this.$refs['processApproval'].handleProcessApproval().then(res => { | ||||
|         this.instance.post(`/app/approval-process-def/add-update`, { | ||||
|           ...this.detailObj, | ||||
|           ...this.baseInfo, | ||||
|           processDefStatus: Number(this.baseInfo.processDefStatus), | ||||
|           tableInfo: { | ||||
|             ...this.detailObj.tableInfo, | ||||
|             tableFieldInfos: this.tableFieldInfos | ||||
|           }, | ||||
|           tableType: 0, | ||||
|           processAnnexDefs: this.annexs.map(e => ({...e, mustFill: Number(e.mustFill)})), | ||||
|           processNodeList: res.processNodeList, | ||||
|           processType: this.processType | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.$message.success("保存成功") | ||||
|             this.$router.push({query:{}}) | ||||
|           } | ||||
|         }) | ||||
|       }).catch(err => { | ||||
|         console.error(err); | ||||
|       }) | ||||
|     }, | ||||
|     getDetail(id) { | ||||
|       this.instance.post(`/app/approval-process-def/info-id`, null, {params: {id}}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.detailObj = res.data | ||||
|           this.filedList = res.data.tableInfo.tableFieldInfos | ||||
|           this.refreshDetail() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getStepIcon(rowIndex) { | ||||
|       if (rowIndex < this.activeStep) return "iconfont iconSteps_Finished" | ||||
|       else if (this.activeStep == rowIndex) return "iconfont iconSteps_In_Progress" | ||||
|       return "" | ||||
|     }, | ||||
|     refreshDetail() { | ||||
|       this.refresh = false | ||||
|       this.$nextTick(() => this.refresh = true) | ||||
|     }, | ||||
|     handleBack() { | ||||
|       this.$router.push({query: {}}) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     if (this.row?.id) { | ||||
|       this.getDetail(this.row?.id) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .add-config { | ||||
|   height: 100%; | ||||
|  | ||||
|   &.formLayout { | ||||
|     ::v-deep .ai-detail__content--wrapper { | ||||
|       max-width: 100%; | ||||
|       height: calc(100%)!important; | ||||
|       padding: 0!important; | ||||
|       overflow: hidden!important; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .step { | ||||
|     width: 100%; | ||||
|     height: 72px; | ||||
|     font-size: 14px; | ||||
|  | ||||
|     .el-steps { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       height: 72px; | ||||
|       padding: 0 calc(50% - 380px); | ||||
|  | ||||
|  | ||||
|       ::v-deep .el-step { | ||||
|         font-weight: bold; | ||||
|  | ||||
|         ::v-deep .el-step__icon { | ||||
|           width: 24px; | ||||
|           height: 24px; | ||||
|           background: #fff; | ||||
|  | ||||
|           .iconfont { | ||||
|             font-size: 24px; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         ::v-deep .el-step__main { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|  | ||||
|           .el-step__arrow { | ||||
|             background: #D0D4DC; | ||||
|             margin: 0 8px; | ||||
|             height: 2px; | ||||
|  | ||||
|             &:before, &:after { | ||||
|               display: none; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .is-process { | ||||
|           color: #2266FF; | ||||
|         } | ||||
|  | ||||
|         .is-wait { | ||||
|           color: #666; | ||||
|           border-color: #D0D4DC; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|     } | ||||
|  | ||||
|   } | ||||
|  | ||||
|   .btn { | ||||
|     width: 92px; | ||||
|     height: 32px; | ||||
|  | ||||
|     &:nth-child(2) { | ||||
|       margin-left: 24px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,895 @@ | ||||
| <template> | ||||
|   <div class="form-config"> | ||||
|     <el-scrollbar class="left"> | ||||
|       <div class="left-item" v-for="(component, index) in components" :key="index"> | ||||
|         <div class="left-item__title"> | ||||
|           <h2>{{ component.label }}</h2> | ||||
|           <span>{{ component.tips }}</span> | ||||
|         </div> | ||||
|         <div class="left-item__list"> | ||||
|           <draggable | ||||
|             class="components-draggable" | ||||
|             :list="component.children" | ||||
|             :group="{ name: 'componentsGroup', pull: 'clone', put: false }" | ||||
|             :sort="false" | ||||
|             :move="onMove" | ||||
|             :clone="cloneComponent" | ||||
|             @end="onEnd"> | ||||
|             <div class="left-item__item" v-for="(item, i) in component.children" :key="i" @click="clone(item)"> | ||||
|               <i class="iconfont" :class="item.icon"></i> | ||||
|               <span>{{ item.fixedLabel }}</span> | ||||
|             </div> | ||||
|           </draggable> | ||||
|         </div> | ||||
|       </div> | ||||
|     </el-scrollbar> | ||||
|     <el-scrollbar class="middle"> | ||||
|       <div class="middle-content"> | ||||
|         <div class="middle-content__wrapper"> | ||||
|           <el-form label-width="100px" label-position="right"> | ||||
|             <draggable | ||||
|               class="middle-draggable" | ||||
|               style="height: 100%;" | ||||
|               :animation="340" | ||||
|               scroll | ||||
|               v-model="targetList" | ||||
|               element="div" | ||||
|               @end="onElEnd" | ||||
|               :sort="true"> | ||||
|               <ai-card | ||||
|                 :class="[groupIndex === j && isGroup ? 'active' : '']" | ||||
|                 :data-index="j" | ||||
|                 @click.native.stop="groupIndex = j, activeIndex = -1, isGroup = true" | ||||
|                 :title="group.groupName" v-for="(group, j) in targetList" | ||||
|                 :key="j"> | ||||
|                 <template #content> | ||||
|                   <draggable | ||||
|                     class="ai-form" | ||||
|                     style="height: 100%;" | ||||
|                     v-model="group.column" | ||||
|                     :animation="340" | ||||
|                     scroll | ||||
|                     @end="onElEnd" | ||||
|                     element="div" | ||||
|                     draggable=".components-item" | ||||
|                     group="componentsGroup" | ||||
|                     :sort="true"> | ||||
|                     <div | ||||
|                       class="components-item" | ||||
|                       v-for="(item, i) in group.column" | ||||
|                       :style="{width: item.grid * 100 + '%'}" | ||||
|                       :class="[groupIndex === j && activeIndex === i ? 'active' : '']" | ||||
|                       @click.stop="groupIndex = j, activeIndex = i, isGroup = false" | ||||
|                       :key="i"> | ||||
|                       <div class="left-item__item--remove" title="删除字段" v-show="groupIndex === j && activeIndex === i" @click.stop="removeItem(j, i)"> | ||||
|                         <i class="iconfont iconDelete"></i> | ||||
|                         <span>删除字段</span> | ||||
|                       </div> | ||||
|                       <el-form-item style="width: 100%;" :label="item.fieldName" :rules="[{ required: item.mustFill === '1' ? true : false }]"> | ||||
|                         <template v-if="item.fieldDataType === '1'"> | ||||
|                           <el-input :disabled="item.disable === '1'" size="small" placeholder="请输入" v-model="item.defaultValue"></el-input> | ||||
|                         </template> | ||||
|                         <template v-if="item.fieldDataType === '4'"> | ||||
|                           <el-radio-group v-model="item.defaultValue" :disabled="item.disable === '1'"> | ||||
|                             <el-radio :label="field.label" v-for="(field, index) in item.options" :key="index">{{ field.label }}</el-radio> | ||||
|                           </el-radio-group> | ||||
|                         </template> | ||||
|                         <template v-if="item.fieldDataType === '0'"> | ||||
|                           <el-input-number style="width: 100%;" v-model="item.defaultValue" :placeholder="item.fieldTips"></el-input-number> | ||||
|                         </template> | ||||
|                         <template v-if="item.fieldDataType === '3'"> | ||||
|                           <el-date-picker | ||||
|                             v-model="item.defaultValue" | ||||
|                             size="small" | ||||
|                             :placeholder="item.fieldTips"> | ||||
|                           </el-date-picker> | ||||
|                         </template> | ||||
|                         <template v-if="item.fieldDataType === '8'"> | ||||
|                           <el-date-picker | ||||
|                             v-model="item.defaultValue" | ||||
|                             size="small" | ||||
|                             :placeholder="item.fieldTips"> | ||||
|                           </el-date-picker> | ||||
|                         </template> | ||||
|                         <template v-if="item.fieldDataType === '9'"> | ||||
|                           <el-select :disabled="item.disable === '1'" style="width: 100%;" size="small" :placeholder="item.fieldTips" v-model="item.defaultValue"> | ||||
|                             <el-option | ||||
|                               v-for="(filed, index) in item.options" | ||||
|                               :key="index" | ||||
|                               :label="filed.label" | ||||
|                               :value="filed.label"> | ||||
|                             </el-option> | ||||
|                           </el-select> | ||||
|                         </template> | ||||
|                         <template v-if="item.fieldDataType === '5'" > | ||||
|                           <el-checkbox-group v-model="item.defaultValue" :disabled="item.disable === '1'"> | ||||
|                             <el-checkbox :label="field.label" v-for="(field, index) in item.options" :key="index">{{ field.label }}</el-checkbox> | ||||
|                           </el-checkbox-group> | ||||
|                         </template> | ||||
|                       </el-form-item> | ||||
|                     </div> | ||||
|                   </draggable> | ||||
|                 </template> | ||||
|               </ai-card> | ||||
|             </draggable> | ||||
|           </el-form> | ||||
|         </div> | ||||
|       </div> | ||||
|     </el-scrollbar> | ||||
|     <el-scrollbar class="right"> | ||||
|       <div class="right-item" v-if="isGroup"> | ||||
|         <div class="right-item__title no-solid"> | ||||
|           <h2>分组名称</h2> | ||||
|         </div> | ||||
|         <div class="right-item__content"> | ||||
|           <el-input placeholder="请输入分组名称" :maxlength="32" show-word-limit v-model="currTarget.groupName"></el-input> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="layout-right__del" @click="removeGroup" v-if="isGroup && targetList.length > 1"> | ||||
|         <span>删除分组</span> | ||||
|       </div> | ||||
|       <div class="right-item" v-if="activeIndex > -1"> | ||||
|         <div class="right-item__title no-solid"> | ||||
|           <h2>标题名称</h2> | ||||
|         </div> | ||||
|         <div class="right-item__content"> | ||||
|           <el-input placeholder="标题名称" :maxlength="32" show-word-limit v-model="currTarget.fieldName"></el-input> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="right-item right-item__select" v-if="['9', '4', '5'].includes(currTarget.fieldDataType)"> | ||||
|         <div class="right-item__title no-solid"> | ||||
|           <h2>选项设置</h2> | ||||
|         </div> | ||||
|         <div class="right-item__select--wrapper"> | ||||
|           <draggable | ||||
|             v-model="currTarget.options" | ||||
|             :animation="340" | ||||
|             group="select" | ||||
|             handle=".mover" | ||||
|             :sort="true"> | ||||
|             <div class="select-item" v-for="(item, index) in currTarget.options" :key="index"> | ||||
|               <i class="iconfont iconjdq_led_show mover"></i> | ||||
|               <el-input placeholder="请输入选项名" :maxlength="30" show-word-limit v-model="item.label"></el-input> | ||||
|               <i class="iconfont iconDelete" @click="removeOptions(index)"></i> | ||||
|             </div> | ||||
|           </draggable> | ||||
|         </div> | ||||
|         <el-button type="text" class="add-select" @click="addOptions">添加选项</el-button> | ||||
|       </div> | ||||
|       <div class="right-item__group" v-if="activeIndex > -1" key="radio"> | ||||
|         <div class="right-item" v-if="currTarget.fieldDataType == 1 || currTarget.fieldDataType == 0"> | ||||
|           <div class="right-item__title"> | ||||
|             <h2>最多输入字符</h2> | ||||
|           </div> | ||||
|           <div class="right-item__content"> | ||||
|             <el-input placeholder="字符个数" v-model="currTarget.fieldLength"> | ||||
|               <span slot="append">个</span> | ||||
|             </el-input> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="right-item"> | ||||
|           <div class="right-item__title no-solid"> | ||||
|             <div class="right-item__title--left"> | ||||
|               <h2>是否必填</h2> | ||||
|             </div> | ||||
|             <el-switch v-model="currTarget.mustFill" active-value="1" inactive-value="0"></el-switch> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </el-scrollbar> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import draggable from 'vuedraggable' | ||||
|   import { components } from './config' | ||||
|  | ||||
|   export default { | ||||
|     name: 'applyForm', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object, | ||||
|       type: String, | ||||
|       value: Array | ||||
|     }, | ||||
|  | ||||
|     components: { | ||||
|       draggable | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         isGroup: false, | ||||
|         components: components, | ||||
|         targetList: [{ | ||||
|           type: 'group', | ||||
|           fieldName: '卡片', | ||||
|           fixedLabel: '卡片', | ||||
|           icon: 'iconpic', | ||||
|           groupName: '基础信息', | ||||
|           column: [] | ||||
|         }], | ||||
|         groupIndex: -1, | ||||
|         activeIndex: -1, | ||||
|         currTarget: {} | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     watch: { | ||||
|       activeIndex () { | ||||
|         if (this.activeIndex > -1 && this.groupIndex > -1 && !this.isGroup) { | ||||
|           const filed = this.targetList[this.groupIndex].column[this.activeIndex] | ||||
|           this.currTarget = filed | ||||
|  | ||||
|           return | ||||
|         } | ||||
|  | ||||
|         if (this.groupIndex > -1 && this.isGroup) { | ||||
|           this.currTarget = this.targetList[this.groupIndex].column[this.activeIndex] | ||||
|  | ||||
|           return  | ||||
|         } | ||||
|  | ||||
|         this.currTarget = {} | ||||
|       }, | ||||
|  | ||||
|       groupIndex () { | ||||
|         if (this.activeIndex > -1 && this.groupIndex > -1 && !this.isGroup) { | ||||
|           const filed = this.targetList[this.groupIndex].column[this.activeIndex] | ||||
|           this.currTarget = filed | ||||
|  | ||||
|           return | ||||
|         } | ||||
|  | ||||
|         if (this.groupIndex > -1 && this.isGroup) { | ||||
|           this.currTarget = this.targetList[this.groupIndex] | ||||
|           return  | ||||
|         } | ||||
|  | ||||
|         this.currTarget = {} | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|       this.init() | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       removeItem (j, i) { | ||||
|         this.groupIndex = -1 | ||||
|         this.activeIndex = -1 | ||||
|         this.targetList[j].column.splice(i, 1) | ||||
|       }, | ||||
|  | ||||
|       init () { | ||||
|         if (this.value.length) { | ||||
|           let arr = this.value | ||||
|           let groups = this.unique(arr.map(v => v.groupName)) | ||||
|           this.targetList = groups.map(groupName => { | ||||
|             const column = arr.filter(v => v.groupName === groupName).map(item => { | ||||
|               if (['9', '4', '5'].includes(item.fieldDataType)) { | ||||
|                 item.options = item.selectValues.split('`').map(v => { | ||||
|                   return { | ||||
|                     label: v, | ||||
|                     value: '' | ||||
|                   } | ||||
|                 }) | ||||
|               } | ||||
|  | ||||
|               if (item.fieldDataType === '5') { | ||||
|                   item.defaultValue = [] | ||||
|               } | ||||
|  | ||||
|               return { | ||||
|                 ...item, | ||||
|                 grid: 1 | ||||
|               } | ||||
|             }) | ||||
|  | ||||
|             return { | ||||
|               type: 'group', | ||||
|               fieldName: '卡片', | ||||
|               fixedLabel: '卡片', | ||||
|               icon: 'iconpic', | ||||
|               groupName, | ||||
|               column: column | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       removeGroup () { | ||||
|         if (this.targetList.length === 1) { | ||||
|           return this.$message.error('分组不能小于1') | ||||
|         } | ||||
|  | ||||
|         this.targetList.splice(this.groupIndex, 1) | ||||
|         this.groupIndex = 0 | ||||
|         this.isGroup = true | ||||
|         this.activeIndex = -1 | ||||
|       }, | ||||
|  | ||||
|       unique (arr) { | ||||
|         return arr.filter((item, index) => { | ||||
|           return arr.indexOf(item, 0) === index | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onConfirm () { | ||||
|         let result = [] | ||||
|         this.targetList.forEach((group, i) => { | ||||
|           group.column.forEach(item => { | ||||
|             result.push({ | ||||
|               ...item, | ||||
|               groupIndex: i, | ||||
|               groupName: group.groupName, | ||||
|               selectValues: item.options ? item.options.map(v => v.label).join('`') : '' | ||||
|             }) | ||||
|           }) | ||||
|         }) | ||||
|  | ||||
|         return new Promise(resolve => { | ||||
|           resolve(result) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       addOptions () { | ||||
|         const len = this.targetList[this.groupIndex].column[this.activeIndex].options.length | ||||
|         let label = `选项${len + 1}` | ||||
|  | ||||
|         const index= this.targetList[this.groupIndex].column[this.activeIndex].options.findIndex(v => label === v.label) | ||||
|         if (index > -1) { | ||||
|           label = `新选项${len + 1}` | ||||
|         } | ||||
|  | ||||
|         this.targetList[this.groupIndex].column[this.activeIndex].options.push({ | ||||
|           label: label, | ||||
|           value: '' | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       removeOptions (index) { | ||||
|         const len = this.targetList[this.groupIndex].column[this.activeIndex].options.length | ||||
|  | ||||
|         if (len === 2) { | ||||
|           return this.$message.error('选项不能少于2个') | ||||
|         } | ||||
|         this.targetList[this.groupIndex].column[this.activeIndex].options.splice(index, 1) | ||||
|       }, | ||||
|  | ||||
|       onEnd (e) { | ||||
|         const el = e.to.parentElement.parentElement | ||||
|         this.isGroup = false | ||||
|         this.activeIndex = e.newIndex | ||||
|         this.groupIndex = Number(el.getAttribute('data-index')) | ||||
|       }, | ||||
|  | ||||
|       onElEnd (e) { | ||||
|         if (this.isGroup) { | ||||
|           this.groupIndex = e.newIndex | ||||
|         } else { | ||||
|           this.activeIndex = e.newIndex | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       clone (e) { | ||||
|         if (e.type === 'group') { | ||||
|           this.targetList.push(JSON.parse(JSON.stringify(e))) | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             this.isGroup = true | ||||
|             this.groupIndex = this.targetList.length - 1 | ||||
|             this.activeIndex = -1 | ||||
|           }) | ||||
|  | ||||
|           return | ||||
|         } | ||||
|  | ||||
|         if (this.isGroup) { | ||||
|           this.targetList[this.groupIndex].column.push(JSON.parse(JSON.stringify(e))) | ||||
|         } else { | ||||
|           this.targetList[0].column.push(JSON.parse(JSON.stringify(e))) | ||||
|         } | ||||
|  | ||||
|         this.$nextTick(() => { | ||||
|           this.groupIndex = this.isGroup ? this.groupIndex : 0 | ||||
|           this.activeIndex = this.targetList[0].column.length - 1 | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onMove (e) { | ||||
|         const el = e.draggedContext.element | ||||
|         if (el.type === 'group') { | ||||
|           return false | ||||
|         } | ||||
|  | ||||
|         return true | ||||
|       }, | ||||
|  | ||||
|       cloneComponent (e) { | ||||
|         if (e.type === 'group') { | ||||
|           this.targetList.push(JSON.parse(JSON.stringify(e))) | ||||
|  | ||||
|           return | ||||
|         } | ||||
|  | ||||
|         return JSON.parse(JSON.stringify(e)) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .layout-right__del { | ||||
|     position: absolute; | ||||
|     bottom: 100px; | ||||
|     left: 0; | ||||
|     z-index: 11; | ||||
|     width: 100%; | ||||
|     padding: 0 16px; | ||||
|  | ||||
|     span { | ||||
|       display: block; | ||||
|       width: 100%; | ||||
|       height: 40px; | ||||
|       line-height: 40px; | ||||
|       text-align: center; | ||||
|       border-radius: 6px; | ||||
|       color: #F46; | ||||
|       cursor: pointer; | ||||
|       border: 1px solid #F46; | ||||
|  | ||||
|       &:hover { | ||||
|         opacity: 0.7; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .form-config { | ||||
|     display: flex; | ||||
|     height: 100%; | ||||
|     padding: 10px 20px 0; | ||||
|  | ||||
|     .ai-form .el-form-item { | ||||
|       margin-bottom: 0; | ||||
|     } | ||||
|  | ||||
|     .right-item__maintitle { | ||||
|       height: 62px; | ||||
|       line-height: 62px; | ||||
|       margin-bottom: 20px; | ||||
|       border-bottom: 1px solid #EEEEEE; | ||||
|       color: #222222; | ||||
|  | ||||
|       h2 { | ||||
|         font-size: 14px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     ::v-deep .ai-card { | ||||
|       cursor: move; | ||||
|  | ||||
|       &.active { | ||||
|         background: #f6f7ff; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     ::v-deep .ai-detail__content { | ||||
|       height: calc(100% - 52px)!important; | ||||
|       padding: 0!important; | ||||
|       overflow: hidden!important; | ||||
|     } | ||||
|  | ||||
|     .ai-dialog__success { | ||||
|       ::v-deep .ai-dialog__content { | ||||
|         max-height: initial!important; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .middle-draggable { | ||||
|       // display: flex; | ||||
|       // justify-content: space-between; | ||||
|       // flex-wrap: wrap; | ||||
|       .left-item__item { | ||||
|         width: 50%; | ||||
|         min-height: 73px; | ||||
|       } | ||||
|  | ||||
|       .el-date-editor.el-input { | ||||
|         width: 100%; | ||||
|       } | ||||
|  | ||||
|       & > span { | ||||
|         display: block; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         min-height: 600px; | ||||
|         padding-bottom: 20px; | ||||
|       } | ||||
|  | ||||
|       .components-item { | ||||
|         position: relative; | ||||
|         margin-bottom: 16px; | ||||
|         padding: 16px 16px; | ||||
|         cursor: move; | ||||
|  | ||||
|         &::after { | ||||
|           position: absolute; | ||||
|           left: 0; | ||||
|           top: 0; | ||||
|           z-index: 1111; | ||||
|           width: 100%; | ||||
|           height: 100%; | ||||
|           content: ' '; | ||||
|         } | ||||
|  | ||||
|         .left-item__item--remove { | ||||
|           display: flex; | ||||
|           position: absolute; | ||||
|           align-items: center; | ||||
|           justify-content: center; | ||||
|           right: 4px; | ||||
|           top: 4px; | ||||
|           z-index: 1113; | ||||
|           width: 84px; | ||||
|           height: 28px; | ||||
|           background: #FF4466; | ||||
|           border-radius: 2px; | ||||
|           cursor: pointer; | ||||
|           color: #fff; | ||||
|           font-size: 12px; | ||||
|  | ||||
|           i { | ||||
|             margin-right: 6px; | ||||
|             font-size: 12px; | ||||
|  | ||||
|             &:hover { | ||||
|               color: #fff; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           &:hover { | ||||
|             opacity: 0.8; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         &:hover { | ||||
|           background: #f6f7ff; | ||||
|         } | ||||
|  | ||||
|         &.active { | ||||
|           background: #f6f7ff; | ||||
|         } | ||||
|  | ||||
|         .left-item__item--upload { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           justify-content: center; | ||||
|           flex-direction: column; | ||||
|           width: 120px; | ||||
|           height: 120px; | ||||
|           line-height: 1; | ||||
|           border-radius: 6px; | ||||
|           border: 1px dashed #bbb; | ||||
|  | ||||
|           i { | ||||
|             font-size: 24px; | ||||
|             color: #8899bb; | ||||
|           } | ||||
|  | ||||
|           span { | ||||
|             margin-top: 10px; | ||||
|             font-size: 12px; | ||||
|             color: #555; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .text-item { | ||||
|           input { | ||||
|             display: block; | ||||
|             width: 100%; | ||||
|             height: 40px; | ||||
|             border: none; | ||||
|             border-bottom: 1px solid #ddd; | ||||
|  | ||||
|             &:focus { | ||||
|               outline: none; | ||||
|             } | ||||
|  | ||||
|             &:disabled { | ||||
|               background: #fff; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .textarea-item { | ||||
|           textarea { | ||||
|             width: 100%; | ||||
|             height: 120px; | ||||
|             resize: none; | ||||
|             border: 1px solid #ddd; | ||||
|             padding: 10px; | ||||
|  | ||||
|             &:focus { | ||||
|               outline: none; | ||||
|             } | ||||
|  | ||||
|             &:disabled { | ||||
|               background: #fff; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .radio-item { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           margin-bottom: 10px; | ||||
|  | ||||
|           &:last-child { | ||||
|             margin-bottom: 0; | ||||
|           } | ||||
|  | ||||
|           label { | ||||
|             margin-left: 10px; | ||||
|           } | ||||
|  | ||||
|           img { | ||||
|             margin-left: 10px; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .left-item__item--title { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         margin-bottom: 10px; | ||||
|  | ||||
|         i { | ||||
|           margin-right: 5px; | ||||
|           color: #E22120; | ||||
|         } | ||||
|  | ||||
|         h2 { | ||||
|           color: #333333; | ||||
|           font-size: 15px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .middle-content { | ||||
|       width: 96%; | ||||
|       margin: 0 auto; | ||||
|       padding: 0px 0 1px; | ||||
|  | ||||
|       .middle-content__wrapper { | ||||
|         // min-height: 800px; | ||||
|         // background: #fff; | ||||
|  | ||||
|         & > div { | ||||
|           &.active { | ||||
|             background: #f6f7ff; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .radio-item { | ||||
|           img { | ||||
|             width: 40px; | ||||
|             height: 40px; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     div { | ||||
|       box-sizing: border-box; | ||||
|     } | ||||
|  | ||||
|     .right-item__select--wrapper { | ||||
|       .select-item { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     ::v-deep .ai-detail__title { | ||||
|       margin: 0!important; | ||||
|       margin-bottom: 4px!important; | ||||
|       padding: 0 20px; | ||||
|       box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.08); | ||||
|     } | ||||
|  | ||||
|     ::v-deep .ai-detail__content--wrapper { | ||||
|       display: flex; | ||||
|       max-width: 100%!important; | ||||
|       height: 100%!important; | ||||
|       padding: 0!important; | ||||
|       background: #F5F6F9; | ||||
|     } | ||||
|  | ||||
|     .middle { | ||||
|       flex: 1; | ||||
|       height: 100%; | ||||
|  | ||||
|       ::v-deep .el-scrollbar__view { | ||||
|         height: 100%; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .add-select { | ||||
|       height: auto; | ||||
|       line-height: 1; | ||||
|       margin: 10px 0 0 26px; | ||||
|       padding: 0; | ||||
|     } | ||||
|  | ||||
|     .right-item__select--wrapper { | ||||
|       .select-item { | ||||
|         margin-bottom: 10px; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-bottom: 0; | ||||
|         } | ||||
|  | ||||
|         i { | ||||
|           margin-right: 8px; | ||||
|           color: #8c9dbd; | ||||
|         } | ||||
|  | ||||
|         .mover { | ||||
|           cursor: move; | ||||
|         } | ||||
|  | ||||
|         .iconDelete { | ||||
|           cursor: pointer; | ||||
|           margin-left: 10px; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ::v-deep .el-upload-list__item { | ||||
|         width: 40px!important; | ||||
|         height: 40px!important; | ||||
|         object-fit: cover; | ||||
|       } | ||||
|  | ||||
|       .config-item__select { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         justify-content: center; | ||||
|         width: 40px; | ||||
|         height: 40px; | ||||
|         border: 1px solid #D0D4DC; | ||||
|  | ||||
|         &:hover { | ||||
|           opacity: 0.7; | ||||
|         } | ||||
|  | ||||
|         i { | ||||
|           font-size: 18px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .right { | ||||
|       width: 320px; | ||||
|       height: 100%; | ||||
|       overflow-y: auto; | ||||
|       overflow: hidden; | ||||
|       background: #FFFFFF; | ||||
|  | ||||
|       .el-checkbox { | ||||
|         display: block; | ||||
|         margin-bottom: 10px; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-bottom: 0; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .right-item { | ||||
|         margin-top: 20px; | ||||
|         padding: 0 20px; | ||||
|  | ||||
|         .right-item__tips { | ||||
|           margin-top: 10px; | ||||
|           color: #888888; | ||||
|           font-size: 12px; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .right-item__title { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         justify-content: space-between; | ||||
|         margin-bottom: 10px; | ||||
|  | ||||
|         .right-item__title--left { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|  | ||||
|           i { | ||||
|             color: #888888; | ||||
|             font-size: 12px; | ||||
|             font-style: normal; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         h2 { | ||||
|           color: #222222; | ||||
|           font-size: 14px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .left { | ||||
|       width: 280px; | ||||
|       height: 100%; | ||||
|       overflow-y: auto; | ||||
|       overflow: hidden; | ||||
|       background: #FFFFFF; | ||||
|  | ||||
|       .left-item { | ||||
|         padding: 0 20px; | ||||
|  | ||||
|         &:last-child { | ||||
|           padding-bottom: 20px; | ||||
|         } | ||||
|  | ||||
|         .left-item__title { | ||||
|           display: flex; | ||||
|           align-items: baseline; | ||||
|           margin-bottom: 20px; | ||||
|  | ||||
|           h2 { | ||||
|             color: #222222; | ||||
|             font-size: 14px; | ||||
|             font-weight: 700; | ||||
|           } | ||||
|  | ||||
|           span { | ||||
|             color: #888888; | ||||
|             font-size: 12px; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .left-item { | ||||
|         margin-top: 20px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .left-item__item { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     height: 40px; | ||||
|     margin-bottom: 10px; | ||||
|     width: 100%; | ||||
|     padding: 0 13px; | ||||
|     background: #FFFFFF; | ||||
|     border-radius: 2px; | ||||
|     color: #222222; | ||||
|     font-size: 12px; | ||||
|     border: 1px solid #E4E8EF; | ||||
|     cursor: move; | ||||
|  | ||||
|     &:hover { | ||||
|       border: 1px dashed #2367ff; | ||||
|       color: #2367ff; | ||||
|  | ||||
|       i { | ||||
|         color: #2367ff; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     i { | ||||
|       margin-right: 13px; | ||||
|       font-size: 14px; | ||||
|       color: #8899BB; | ||||
|     } | ||||
|  | ||||
|     &:last-child { | ||||
|       margin-bottom: 0px; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
| @@ -0,0 +1,196 @@ | ||||
| <template> | ||||
|   <div class="attachment-material"> | ||||
|     <ai-card title="附件材料"> | ||||
|       <template #right> | ||||
|         <span class="iconfont iconAdd rightBtn"></span> | ||||
|         <span class="rightBtn" style="margin-left: 8px;" @click="dialog=true">新增行数</span> | ||||
|       </template> | ||||
|       <template #content> | ||||
|         <el-table | ||||
|           :data="materialList" | ||||
|           stripe | ||||
|           style="width: 100%" | ||||
|           header-cell-class-name="table-header" | ||||
|           align="center" | ||||
|           empty-text="材料列表信息为空,点击标题右侧添加按钮进行添加" | ||||
|         > | ||||
|           <el-table-column align="left" prop="annexName" label="材料名称" width="280"> | ||||
|             <template slot-scope="scope"> | ||||
|               <div class="table-border">{{ scope.row.annexName }}</div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column align="center" prop="exampleFileId" label="样例"> | ||||
|             <template slot-scope="{row}"> | ||||
|               <el-upload action :on-exceed="list=>handleUpload({file:list[0]}).then(v=>row.exampleFileId=v)" | ||||
|                          :http-request="args=>handleUpload(args).then(v=>row.exampleFileId=v)" :limit="1" accept=".jpg,.png"> | ||||
|                 <el-button style="width: 102px">{{ row.exampleFileId ? '重新选择图片' : '选择图片文件' }}</el-button> | ||||
|               </el-upload> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column align="center" prop="emptyFileId" label="空表"> | ||||
|             <template slot-scope="{row}"> | ||||
|               <el-upload action :on-exceed="list=>handleUpload({file:list[0]}).then(v=>row.emptyFileId=v)" | ||||
|                          :http-request="args=>handleUpload(args).then(v=>row.emptyFileId=v)" :limit="1" accept=".doc,.docx"> | ||||
|                 <el-button style="width: 102px">{{ row.emptyFileId ? '重新选择word' : '选择word文件' }}</el-button> | ||||
|               </el-upload> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column align="center" prop="name" label="是否必填"> | ||||
|             <template slot-scope="scope"> | ||||
|               <el-switch | ||||
|                 v-model="scope.row.mustFill" | ||||
|                 active-value="1" inactive-value="0" | ||||
|                 active-color="#5088FF" | ||||
|                 inactive-color="#D0D4DC"> | ||||
|               </el-switch> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column align="center" label="操作"> | ||||
|             <template slot-scope="scope"> | ||||
|               <span class="iconfont iconEdit icon-color89B" title="编辑" @click="editInfo(scope.$index)" style="margin-right: 10px;"/> | ||||
|               <span class="iconfont iconDelete icon-color89B" title="删除" @click="deleteInfo(scope.$index)"/> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </el-table> | ||||
|       </template> | ||||
|     </ai-card> | ||||
|     <ai-dialog | ||||
|         title="添加附件材料" | ||||
|         :visible.sync="dialog" | ||||
|         @closed="form.annexName='',idAdd=true,index=null" | ||||
|         @onConfirm="onConfirm" | ||||
|         @onCancel="dialog=false" | ||||
|         width="720px"> | ||||
|       <el-form :rules="rules" ref="materialForm" label-width="100px" :model="form"> | ||||
|         <el-form-item label="材料名称:" prop="annexName"> | ||||
|           <el-input v-model.trim="form.annexName" size="small" placeholder="请输入材料名称" show-word-limit :maxlength="32"/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "attachmentMaterial", | ||||
|   inject: ['config'], | ||||
|   props: { | ||||
|     instance: Function, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       materialList: [], | ||||
|       dialog: false, | ||||
|       idAdd: true, | ||||
|       index: null, | ||||
|       form: { | ||||
|         annexName: "" | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     rules() { | ||||
|       return { | ||||
|         annexName: [{required: true, message: '请输入材料名称', trigger: 'blur'}] | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleAttachmentMaterial() { | ||||
|       return Promise.resolve(this.materialList) | ||||
|     }, | ||||
|     handleUpload(file) { | ||||
|       let formData = new FormData() | ||||
|       formData.append('file', file.file) | ||||
|       return this.instance.post(`/admin/file/add`, formData).then(res => { | ||||
|         if (res?.code == 0) { | ||||
|           this.$message.success('上传成功') | ||||
|           let data = res.data[0].split(';') | ||||
|           return data[1] | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|      * 添加附件材料 | ||||
|      * */ | ||||
|     onConfirm() { | ||||
|       this.$refs['materialForm'].validate(valid => { | ||||
|         if (valid) { | ||||
|           if(this.idAdd){ | ||||
|             this.materialList.push({ | ||||
|               annexName: this.form.annexName, | ||||
|               mustFill: "1", | ||||
|               exampleFileId: "", | ||||
|               emptyFileId: "", | ||||
|             }) | ||||
|           }else { | ||||
|             this.materialList[this.index].annexName = this.form.annexName | ||||
|           } | ||||
|           this.dialog = false | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|      * 删除 | ||||
|      */ | ||||
|     deleteInfo(index) { | ||||
|       this.$confirm("是否删除?").then(res => { | ||||
|         this.materialList.splice(index, 1) | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|      * 编辑标题 | ||||
|      */ | ||||
|     editInfo(index) { | ||||
|       this.dialog = true | ||||
|       this.idAdd = false | ||||
|       this.index = index | ||||
|       this.form.annexName = JSON.parse(JSON.stringify(this.materialList[index].annexName)) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     if (this.config.detailObj?.id) { | ||||
|       this.materialList = JSON.parse(JSON.stringify(this.config.detailObj?.processAnnexDefs)) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .attachment-material { | ||||
|   .rightBtn { | ||||
|     font-size: 14px; | ||||
|     color: #5088FF; | ||||
|     user-select: none; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|  | ||||
|   .table-border { | ||||
|     width: 260px; | ||||
|     height: 32px; | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 14px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     border-radius: 2px; | ||||
|     border: 1px solid #D0D4DC; | ||||
|     color: #333333; | ||||
|     overflow: hidden; | ||||
|     text-overflow: ellipsis; | ||||
|     white-space: nowrap; | ||||
|   } | ||||
|  | ||||
|   ::v-deep .el-upload-list { | ||||
|     display: none; | ||||
|   } | ||||
|  | ||||
|   .iconDelete { | ||||
|     user-select: none; | ||||
|     cursor: pointer; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,154 @@ | ||||
| <template> | ||||
|   <section class="base-info"> | ||||
|     <ai-card title="基本信息"> | ||||
|       <template #content> | ||||
|         <el-form :model="form" :rules="rules" ref="baseInfoForm" label-suffix=":" label-width="100px"> | ||||
|           <el-form-item label="事项名称" prop="processName"> | ||||
|             <el-input v-model.trim="form.processName" size="small" clearable placeholder="请输入事项名称" :maxlength="30" | ||||
|                       show-word-limit/> | ||||
|           </el-form-item> | ||||
|           <el-row type="type" justify="space-between" :gutter="20"> | ||||
|             <el-col :span="12"> | ||||
|               <el-form-item label="所属部门" prop="department"> | ||||
|                 <el-select placeholder="请选择" size="small" v-model="form.department" clearable style="width: 100%;"> | ||||
|                   <el-option | ||||
|                     v-for="(item,i) in dict.getDict('hbDepartment')" :key="i" | ||||
|                     :label="item.dictName" | ||||
|                     :value="item.dictValue"> | ||||
|                   </el-option> | ||||
|                 </el-select> | ||||
|               </el-form-item> | ||||
|             </el-col> | ||||
|             <el-col :span="12"> | ||||
|               <el-form-item label="所属分类" prop="classificationId"> | ||||
|                 <el-select placeholder="请选择" size="small" v-model="form.classificationId" clearable | ||||
|                            style="width: 100%;"> | ||||
|                   <el-option | ||||
|                     v-for="(item,i) in classList" :key="i" | ||||
|                     :label="item.name" | ||||
|                     :value="item.id"> | ||||
|                   </el-option> | ||||
|                 </el-select> | ||||
|               </el-form-item> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|           <el-form-item label="办结时限" prop="timeLimit"> | ||||
|             <el-input v-model.trim="form.timeLimit" oninput="value=value.replace(/[^\d]/g,'')" size="small" clearable | ||||
|                       placeholder="请输入天数" style="width: 270px;"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="办理须知" prop="needToKnow"> | ||||
|             <ai-editor v-model="form.needToKnow" :instance="instance" @validate="v=>valid=!v"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="是否启用" prop="processDefStatus"> | ||||
|             <el-switch | ||||
|               v-model="form.processDefStatus" | ||||
|               active-color="#5088FF" | ||||
|               inactive-color="#D0D4DC" active-value="1" inactive-value="0"> | ||||
|             </el-switch> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </template> | ||||
|     </ai-card> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
|   export default { | ||||
|     name: "baseInfo", | ||||
|     inject: ['config'], | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|     }, | ||||
|     data() { | ||||
|       const validTimeLimit = (rule, value, callback) => { | ||||
|         if (!value) { | ||||
|           return callback(new Error('请输入办结时限')); | ||||
|         } else { | ||||
|           if (+value <= 0) { | ||||
|             return callback(new Error('最小值为1')); | ||||
|           } | ||||
|           callback(); | ||||
|         } | ||||
|       } | ||||
|       return { | ||||
|         form: { | ||||
|           processName: "", | ||||
|           department: "", | ||||
|           classificationId: "", | ||||
|           timeLimit: "", | ||||
|           needToKnow: "", | ||||
|           processDefStatus: "1", | ||||
|         }, | ||||
|         valid:true, | ||||
|         classList: [], | ||||
|         rules: { | ||||
|           processName: [{required: true, message: '请输入事项名称', trigger: 'blur'}], | ||||
|           department: [{required: true, message: '请选择所属部门', trigger: 'change'}], | ||||
|           classificationId: [{required: true, message: '请选择所属分类', trigger: 'change'}], | ||||
|           timeLimit: [{required: true, validator: validTimeLimit, trigger: 'blur'}], | ||||
|           needToKnow: [ | ||||
|             {required: true, message: '请输入办理须知', trigger: 'blur'}, | ||||
|             { | ||||
|               validator: (r, v, cb) => { | ||||
|                 if (this.valid) { | ||||
|                   cb() | ||||
|                 } else { | ||||
|                   cb('字数超过限制') | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           ], | ||||
|           processDefStatus: [{required: true, message: '请选择是否启用', trigger: 'change'}], | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|       banseInfoForm() { | ||||
|         return new Promise((resolve, reject) => { | ||||
|           this.$refs['baseInfoForm'].validate(valid => { | ||||
|             if (valid) { | ||||
|               resolve(this.form) | ||||
|             } else { | ||||
|               reject(false) | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|       /** | ||||
|        * 获取分类 | ||||
|        */ | ||||
|       getClassification() { | ||||
|         this.instance.post(`/app/zwspapprovalclassification/list`, null, { | ||||
|          params: { | ||||
|            current: 1, | ||||
|            status: 1, | ||||
|            size: 9999 | ||||
|          } | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.classList = res.data.records | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     created() { | ||||
|       this.getClassification() | ||||
|       if (this.config.detailObj?.id) { | ||||
|         this.$nextTick(_=>{ | ||||
|           Object.keys(this.form).map(e => this.form[e] = this.config.detailObj[e]) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .base-info { | ||||
|     .iconAudit { | ||||
|       font-size: 36px; | ||||
|       color: #3D94FB; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
| @@ -0,0 +1,203 @@ | ||||
| export const components = [ | ||||
| 	{ | ||||
| 		type: 'info', | ||||
| 		tips: '(可重复添加)', | ||||
| 		label: '信息', | ||||
| 		children: [ | ||||
| 			{ | ||||
| 				type: 'name', | ||||
| 				fieldName: '姓名', | ||||
| 				fieldTips: '请输入姓名', | ||||
| 				fixedLabel: '姓名', | ||||
| 				disable: '0', | ||||
| 				grid: 1, | ||||
| 				fieldDataType: '1', | ||||
| 				defaultValue: '', | ||||
| 				icon: 'icontext_box', | ||||
| 				mustFill: '1', | ||||
| 				fieldLength: 20 | ||||
| 			}, | ||||
| 			{ | ||||
| 				type: 'idNumber', | ||||
| 				fieldName: '身份证号', | ||||
| 				fixedLabel: '身份证号', | ||||
| 				fieldTips: '请输入身份证号', | ||||
| 				defaultValue: '', | ||||
| 				icon: 'icontext_area', | ||||
| 				mustFill: '1', | ||||
| 				fieldLength: 20, | ||||
| 				disable: '0', | ||||
| 				grid: 1, | ||||
| 				fieldDataType: '1', | ||||
| 				verifyType: 0 | ||||
| 			}, | ||||
| 			{ | ||||
| 				type: 'phone', | ||||
| 				fieldName: '联系方式', | ||||
| 				fixedLabel: '联系方式', | ||||
| 				fieldTips: '请输入联系方式', | ||||
| 				defaultValue: '', | ||||
| 				icon: 'icontext_area', | ||||
| 				mustFill: '1', | ||||
| 				fieldLength: 11, | ||||
| 				disable: '0', | ||||
| 				grid: 1, | ||||
| 				fieldDataType: '1', | ||||
| 				verifyType: 1 | ||||
| 			} | ||||
| 		] | ||||
| 	}, | ||||
| 	{ | ||||
| 		type: 'options', | ||||
| 		tips: '(可重复添加)', | ||||
| 		label: '选项', | ||||
| 		children: [ | ||||
| 			{ | ||||
| 				type: 'radio', | ||||
| 				fieldName: '单选', | ||||
| 				fixedLabel: '单选', | ||||
| 				fieldTips: '请选择', | ||||
| 				grid: 1, | ||||
| 				icon: 'iconradio', | ||||
| 				mustFill: '1', | ||||
| 				disable: '0', | ||||
| 				fieldDataType: '4', | ||||
| 				defaultValue: '', | ||||
| 				options: [ | ||||
| 					{ | ||||
| 						label: '选项1', | ||||
| 						value: '' | ||||
| 					}, | ||||
| 					{ | ||||
| 						label: '选项2', | ||||
| 						value: '' | ||||
| 					} | ||||
| 				], | ||||
| 				title: '' | ||||
| 			}, | ||||
| 			{ | ||||
| 				type: 'checkbox', | ||||
| 				fieldName: '多选', | ||||
| 				fixedLabel: '多选', | ||||
| 				fieldTips: '请选择', | ||||
| 				icon: 'iconcheck_box', | ||||
| 				fieldDataType: '5', | ||||
| 				mustFill: '1', | ||||
| 				grid: 1, | ||||
| 				disable: '0', | ||||
| 				defaultValue: [], | ||||
| 				options: [ | ||||
| 					{ | ||||
| 						label: '选项1', | ||||
| 						value: '' | ||||
| 					}, | ||||
| 					{ | ||||
| 						label: '选项2', | ||||
| 						value: '' | ||||
| 					} | ||||
| 				], | ||||
| 				title: '' | ||||
| 			}, | ||||
| 			{ | ||||
| 				type: 'select', | ||||
| 				fieldName: '单下拉框', | ||||
| 				fixedLabel: '单下拉框', | ||||
| 				grid: 1, | ||||
| 				fieldTips: '请选择', | ||||
| 				icon: 'iconSelect', | ||||
| 				mustFill: '1', | ||||
| 				defaultValue: '', | ||||
| 				fieldDataType: '9', | ||||
| 				disable: '0', | ||||
| 				options: [ | ||||
| 					{ | ||||
| 						label: '选项1', | ||||
| 						value: '' | ||||
| 					}, | ||||
| 					{ | ||||
| 						label: '选项2', | ||||
| 						value: '' | ||||
| 					} | ||||
| 				], | ||||
| 				title: '' | ||||
| 			}, | ||||
| 			{ | ||||
| 				type: 'date', | ||||
| 				fieldName: '日期', | ||||
| 				fixedLabel: '日期', | ||||
| 				grid: 1, | ||||
| 				fieldDataType: '3', | ||||
| 				datetimePattern: 'yyyy-MM-dd', | ||||
| 				fieldTips: '请选择日期', | ||||
| 				icon: 'iconSelect', | ||||
| 				mustFill: '1', | ||||
| 				disable: '0', | ||||
| 				title: '' | ||||
| 			}, | ||||
| 			{ | ||||
| 				type: 'datetime', | ||||
| 				fieldName: '日期时间', | ||||
| 				fixedLabel: '日期时间', | ||||
| 				grid: 1, | ||||
| 				fieldDataType: '8', | ||||
| 				datetimePattern: 'yyyy-MM-dd HH:mm:ss', | ||||
| 				fieldTips: '请选择日期时间', | ||||
| 				icon: 'iconSelect', | ||||
| 				mustFill: '1', | ||||
| 				disable: '0', | ||||
| 				title: '' | ||||
| 			} | ||||
| 		] | ||||
| 	}, | ||||
| 	{ | ||||
| 		type: 'input', | ||||
| 		tips: '(可重复添加)', | ||||
| 		label: '填空', | ||||
| 		children: [ | ||||
| 			{ | ||||
| 				type: 'input', | ||||
| 				fieldName: '单行填空', | ||||
| 				fieldTips: '请输入', | ||||
| 				fixedLabel: '单行填空', | ||||
| 				disable: '0', | ||||
| 				grid: 1, | ||||
| 				fieldDataType: '1', | ||||
| 				defaultValue: '', | ||||
| 				icon: 'icontext_box', | ||||
| 				mustFill: '1', | ||||
| 				fieldLength: 50 | ||||
| 			}, | ||||
| 			{ | ||||
| 				type: 'number', | ||||
| 				fieldName: '数字输入', | ||||
| 				fixedLabel: '数字输入', | ||||
| 				fieldTips: '请输入数字', | ||||
| 				defaultValue: '', | ||||
| 				icon: 'icontext_area', | ||||
| 				mustFill: '1', | ||||
| 				maxValue: 10000, | ||||
| 				decimalPlaces: 0, | ||||
| 				fieldDataType: '0', | ||||
| 				minValue: 0, | ||||
| 				fieldLength: 50, | ||||
| 				disable: '0', | ||||
| 				grid: 1, | ||||
| 			} | ||||
| 		] | ||||
| 	}, | ||||
| 	{ | ||||
| 		type: 'layout', | ||||
| 		tips: '(可重复添加)', | ||||
| 		label: '分组', | ||||
| 		children: [ | ||||
| 			{ | ||||
| 				type: 'group', | ||||
| 				fieldName: '卡片', | ||||
| 				fixedLabel: '卡片', | ||||
| 				icon: 'iconpic', | ||||
| 				groupName: '分组标题', | ||||
| 				column: [] | ||||
| 			} | ||||
| 		] | ||||
| 	} | ||||
| ]; | ||||
| @@ -0,0 +1,214 @@ | ||||
| <template> | ||||
|   <div class="config-list"> | ||||
|     <ai-list isTabs> | ||||
|       <template #content> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <el-select v-model="search.department" placeholder="请选择所属部门" @change="page.current=1,getList()" | ||||
|                        size="small" clearable> | ||||
|               <el-option | ||||
|                 v-for="(item,i) in dict.getDict('hbDepartment')" :key="i" | ||||
|                 :label="item.dictName" | ||||
|                 :value="item.dictValue"> | ||||
|               </el-option> | ||||
|             </el-select> | ||||
|             <el-select v-model="search.classificationId" placeholder="请选择所属分类" @change="page.current=1,getList()" | ||||
|                        size="small" clearable> | ||||
|               <el-option | ||||
|                 v-for="(item,i) in classList" :key="i" | ||||
|                 :label="item.name" | ||||
|                 :value="item.id"> | ||||
|               </el-option> | ||||
|             </el-select> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input | ||||
|               v-model="search.processName" | ||||
|               size="small" | ||||
|               placeholder="事项名称/创建人" | ||||
|               @clear="search={},page.current=1,getList()" | ||||
|               @keyup.enter.native="page.current=1,getList()" | ||||
|               clearable | ||||
|               suffix-icon="iconfont iconSearch"/> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <el-button type="primary" icon="iconfont iconAdd" @click="goPage(tab.value==0 ? 'addConfig':'guidance')">添加{{tab.value==0?'事项':'办事指南'}}</el-button> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table | ||||
|           :tableData="tableData" | ||||
|           :col-configs="colConfigs" | ||||
|           :header-cell-style="{fontWeight:'bold',color:'#333'}" | ||||
|           :total="page.total" | ||||
|           :current.sync="page.current" | ||||
|           :size.sync="page.size" | ||||
|           @getList="getList"> | ||||
|           <el-table-column label="是否启用" slot="processDefStatus" align="center" width="150"> | ||||
|             <template v-slot="{row}"> | ||||
|               <el-switch | ||||
|                 v-model="row.processDefStatus" | ||||
|                 @change="onChange(row)" active-value="1" inactive-value="0" | ||||
|                 active-color="#5088FF" | ||||
|                 inactive-color="#D0D4DC"> | ||||
|               </el-switch> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column label="操作" slot="options" align="center" width="150"> | ||||
|             <template v-slot="{row}"> | ||||
|               <div class="table-options"> | ||||
|                 <el-button type="text" title="编辑" @click="goPage(tab.value==0 ? 'addConfig':'guidance',row)">编辑</el-button> | ||||
|                 <el-button type="text" title="删除" @click="delInfo(row)">删除</el-button> | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import day from 'dayjs' | ||||
|  | ||||
|   export default { | ||||
|     name: "configList", | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function, | ||||
|       tab: Object, | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           department: "", | ||||
|           classificationId: "", | ||||
|           processName: "", | ||||
|         }, | ||||
|         page: {current: 1, size: 10}, | ||||
|         total: 0, | ||||
|         row: {}, | ||||
|         tableData: [], | ||||
|         classList: [], | ||||
|       } | ||||
|     }, | ||||
|     computed: { | ||||
|       colConfigs() { | ||||
|         return [ | ||||
|           { | ||||
|             prop: 'processName', | ||||
|             align: 'left', | ||||
|             label: '事项名称', | ||||
|           }, | ||||
|           { | ||||
|             prop: 'department', | ||||
|             align: 'left', | ||||
|             label: '所属部门', | ||||
|             render: (h, {row}) => [ < span > {this.dict.getLabel('hbDepartment', row.department)} < /span>] | ||||
|           }, | ||||
|           { | ||||
|             prop: 'classificationName', | ||||
|             align: 'center', | ||||
|             label: '所属分类', | ||||
|           }, | ||||
|           { | ||||
|             prop: 'timeLimit', | ||||
|             align: 'center', | ||||
|             label: '办结时限(日)', | ||||
|           }, | ||||
|           { | ||||
|             prop: 'createUserName', | ||||
|             align: 'center', | ||||
|             label: '创建人', | ||||
|           }, | ||||
|           { | ||||
|             prop: 'createTime', | ||||
|             align: 'center', | ||||
|             label: '最后修改时间', | ||||
|             render: (h, {row}) => [ < span > {day(row.createTime | ||||
|       ). | ||||
|         format("YYYY-MM-DD HH:mm") | ||||
|       }< | ||||
|         /span>] | ||||
|       }, | ||||
|         {slot: 'processDefStatus', align:'center', label:'是否启用',}, | ||||
|         { slot: 'options',align:'center',label:'操作',}, | ||||
|       ].filter(e=>this.tab.value==0 ? true : (e.prop!="timeLimit")) | ||||
|       }, | ||||
|     }, | ||||
|     methods: { | ||||
|       goPage(comp, row = {}) { | ||||
|         this.$emit("goPage", {comp, row}) | ||||
|       }, | ||||
|       /** | ||||
|        * 获取分类 | ||||
|        */ | ||||
|       getClassification() { | ||||
|         this.instance.post(`/app/zwspapprovalclassification/list`, null, { | ||||
|           params:{ | ||||
|             current: 1, | ||||
|             status: 1, | ||||
|             size: 9999 | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res && res.data) { | ||||
|             this.classList = res.data.records | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       /** | ||||
|        * 删除 | ||||
|        * */ | ||||
|       delInfo({id}) { | ||||
|         this.$confirm("是否删除").then(() => { | ||||
|           this.instance.post(`/app/approval-process-def/delete?id=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success("删除成功") | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|       /** | ||||
|        * 启用,停用 | ||||
|        */ | ||||
|       onChange({id, processDefStatus}) { | ||||
|         this.instance.post(`/app/approval-process-def/enable-disable`, null, { | ||||
|           params: {id} | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.$message.success(processDefStatus == 0 ? "不启用" : "已启用") | ||||
|             this.getList() | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getList() { | ||||
|         this.instance.post(`/app/approval-process-def/list`, null, { | ||||
|           params: { | ||||
|             ...this.page, | ||||
|             ...this.search, | ||||
|             processType: this.tab.value | ||||
|           }, | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.tableData = res.data.records | ||||
|             this.page.total = res.data.total; | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|     }, | ||||
|     mounted() { | ||||
|       this.getList() | ||||
|       this.getClassification() | ||||
|     }, | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .config-list { | ||||
|     height: 100%; | ||||
|   } | ||||
| </style> | ||||
| @@ -0,0 +1,219 @@ | ||||
| <template> | ||||
|   <div class="guidance"> | ||||
|     <ai-detail> | ||||
|       <ai-title slot="title" :title="detailTitle" isShowBack isShowBottomBorder @onBackClick="handleBack"/> | ||||
|       <template #content> | ||||
|         <ai-card title="基本信息"> | ||||
|           <template #content> | ||||
|             <el-form :model="form" :rules="rules" ref="baseInfoForm" label-suffix=":" label-width="100px"> | ||||
|               <el-form-item label="事项名称" prop="processName"> | ||||
|                 <el-input v-model.trim="form.processName" size="small" clearable placeholder="请输入事项名称" :maxlength="30" | ||||
|                           show-word-limit/> | ||||
|               </el-form-item> | ||||
|               <el-row type="type" justify="space-between" :gutter="20"> | ||||
|                 <el-col :span="12"> | ||||
|                   <el-form-item label="所属部门" prop="department"> | ||||
|                     <el-select placeholder="请选择" size="small" v-model="form.department" clearable style="width: 100%;"> | ||||
|                       <el-option | ||||
|                         v-for="(item,i) in dict.getDict('hbDepartment')" :key="i" | ||||
|                         :label="item.dictName" | ||||
|                         :value="item.dictValue"> | ||||
|                       </el-option> | ||||
|                     </el-select> | ||||
|                   </el-form-item> | ||||
|                 </el-col> | ||||
|                 <el-col :span="12"> | ||||
|                   <el-form-item label="所属分类" prop="classificationId"> | ||||
|                     <el-select placeholder="请选择" size="small" v-model="form.classificationId" clearable | ||||
|                                style="width: 100%;"> | ||||
|                       <el-option | ||||
|                         v-for="(item,i) in classList" :key="i" | ||||
|                         :label="item.name" | ||||
|                         :value="item.id"> | ||||
|                       </el-option> | ||||
|                     </el-select> | ||||
|                   </el-form-item> | ||||
|                 </el-col> | ||||
|               </el-row> | ||||
|               <el-form-item label="办理须知" prop="needToKnow"> | ||||
|                 <ai-editor v-model.trim="form.needToKnow" :instance="instance"/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="是否启用" prop="processDefStatus"> | ||||
|                 <el-switch | ||||
|                   v-model="form.processDefStatus" | ||||
|                   active-color="#5088FF" | ||||
|                   inactive-color="#D0D4DC" active-value="1" inactive-value="0"> | ||||
|                 </el-switch> | ||||
|               </el-form-item> | ||||
|             </el-form> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|       </template> | ||||
|       <template #footer> | ||||
|         <el-button class="btn" @click="handleBack">取消</el-button> | ||||
|         <el-button class="btn" type="primary" @click="save">保存</el-button> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
|   export default { | ||||
|     name: "addConfig", | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       row: Object, | ||||
|       processType: String | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         form: { | ||||
|           processName: "", | ||||
|           department: "", | ||||
|           classificationId: "", | ||||
|           needToKnow: "", | ||||
|           processDefStatus: "1", | ||||
|         }, | ||||
|         classList: [], | ||||
|       } | ||||
|     }, | ||||
|     computed: { | ||||
|       rules() { | ||||
|         return { | ||||
|           processName: [{required: true, message: '请输入事项名称', trigger: 'blur'}], | ||||
|           department: [{required: true, message: '请选择所属部门', trigger: 'change'}], | ||||
|           classificationId: [{required: true, message: '请选择所属分类', trigger: 'change'}], | ||||
|           needToKnow: [{required: true, message: '请输入办理须知', trigger: 'blur'}], | ||||
|           processDefStatus: [{required: true, message: '请选择是否启用', trigger: 'change'}], | ||||
|         } | ||||
|       }, | ||||
|       detailTitle() { | ||||
|         return this.row?.id ? "编辑办事指南" : "添加办事指南" | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|       /** | ||||
|        * 获取分类 | ||||
|        */ | ||||
|       getClassification() { | ||||
|         this.instance.post(`/app/zwspapprovalclassification/list`, null, { | ||||
|           params: { | ||||
|             current: 1, | ||||
|             status: 1, | ||||
|             size: 9999 | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.classList = res.data.records | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       /** | ||||
|        * 保存 | ||||
|        */ | ||||
|       save() { | ||||
|         this.$refs["baseInfoForm"].validate(valid => { | ||||
|           if (valid) { | ||||
|             this.instance.post(`/app/approval-process-def/add-update`, { | ||||
|               ...this.form, | ||||
|               id: this.row.id, | ||||
|               processType: this.processType | ||||
|             }).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success("保存成功") | ||||
|                 this.$router.push({query: {}}) | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       getDetail(id) { | ||||
|         this.instance.post(`/app/approval-process-def/info-id`, null, {params: {id}}).then(res => { | ||||
|           if (res?.data) { | ||||
|             Object.keys(this.form).map(e => this.form[e] = res.data[e]) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       handleBack() { | ||||
|         this.$router.push({query: {}}) | ||||
|       } | ||||
|     }, | ||||
|     created() { | ||||
|       this.getClassification() | ||||
|       if (this.row?.id) { | ||||
|         this.getDetail(this.row?.id) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .add-config { | ||||
|     height: 100%; | ||||
|  | ||||
|     .step { | ||||
|       width: 100%; | ||||
|       height: 72px; | ||||
|       font-size: 14px; | ||||
|  | ||||
|       .el-steps { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         height: 72px; | ||||
|         padding: 0 calc(50% - 380px); | ||||
|  | ||||
|  | ||||
|         ::v-deep .el-step { | ||||
|           font-weight: bold; | ||||
|  | ||||
|           ::v-deep .el-step__icon { | ||||
|             width: 24px; | ||||
|             height: 24px; | ||||
|             background: #fff; | ||||
|  | ||||
|             .iconfont { | ||||
|               font-size: 24px; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           ::v-deep .el-step__main { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|  | ||||
|             .el-step__arrow { | ||||
|               background: #D0D4DC; | ||||
|               margin: 0 8px; | ||||
|               height: 2px; | ||||
|  | ||||
|               &:before, &:after { | ||||
|                 display: none; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           .is-process { | ||||
|             color: #2266FF; | ||||
|           } | ||||
|  | ||||
|           .is-wait { | ||||
|             color: #666; | ||||
|             border-color: #D0D4DC; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|       } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     .btn { | ||||
|       width: 92px; | ||||
|       height: 32px; | ||||
|  | ||||
|       &:nth-child(2) { | ||||
|         margin-left: 24px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
| @@ -0,0 +1,4 @@ | ||||
| export {default as baseInfo} from './baseInfo' | ||||
| export {default as applyForm} from './applyForm' | ||||
| export {default as attachmentMaterial} from './attachmentMaterial' | ||||
| export {default as processApproval} from './processApproval' | ||||
| @@ -0,0 +1,482 @@ | ||||
| <template> | ||||
|   <div class="process-approval"> | ||||
|     <ai-card title="流程设置"> | ||||
|       <template #right> | ||||
|         <span class="iconfont iconAdd rightBtn"></span> | ||||
|         <span class="rightBtn" style="margin-left: 8px;" @click="addAppStep(1)">添加审批步骤</span> | ||||
|       </template> | ||||
|       <template #content> | ||||
|         <el-steps direction="vertical"> | ||||
|           <el-step v-for="(item,index) in form.processNodeList" :key="index"> | ||||
|             <div slot="title" class="step_title"> | ||||
|               <p>{{ item.nodeName }}({{ dict.getLabel('nodeType', item.nodeType) }})</p> | ||||
|               <div class="peraoBtn"> | ||||
|                 <el-button type="text" :disabled="index==0" class="iconfont iconMoveUp" | ||||
|                            @click="form.processNodeList[index] = form.processNodeList.splice(index-1, 1,form.processNodeList[index])[0]"> | ||||
|                   上移 | ||||
|                 </el-button> | ||||
|                 <el-button type="text" :disabled="index==(form.processNodeList.length-1)" class="iconfont iconMoveDown" | ||||
|                            @click="form.processNodeList[index] = form.processNodeList.splice(index+1, 1,form.processNodeList[index])[0]"> | ||||
|                   下移 | ||||
|                 </el-button> | ||||
|                 <el-button type="text" class="iconfont iconEdit" @click="addAppStep(2,item,index)"> | ||||
|                   编辑 | ||||
|                 </el-button> | ||||
|                 <el-button type="text" class="iconfont iconDelete" @click="deleteInfo(index)"> | ||||
|                   删除 | ||||
|                 </el-button> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div slot="description" class="step_desc"> | ||||
|               <div class="desc_style"> | ||||
|                 <p> | ||||
|                   选人方式:<span>{{ dict.getLabel('candidateApproverType', item.candidateApproverType) }}</span> | ||||
|                 </p> | ||||
|               </div> | ||||
|               <div class="desc_person" v-if="item.scopeCandidates==1||item.candidateApproverType==1"> | ||||
|                 <p class="desc_p">指定人员:</p> | ||||
|                 <div class="desc_div"> | ||||
|                   <el-tag type="info" closable v-for="(value,i) in item.candidateList" :key="i" | ||||
|                           @close="item.candidateList.splice(i,1)"> | ||||
|                     {{ value.name }} | ||||
|                   </el-tag> | ||||
|                   <el-button v-if="item.candidateList.length>0" type="text" @click="item.candidateList=[]">清空 | ||||
|                   </el-button> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <ai-wechat-selecter slot="append" :instance="instance" :props="{id:'wxUserId',label:'name'}" | ||||
|                                     v-model="item.candidateList" v-if="item.candidateApproverType==1"> | ||||
|                 <el-button size="mini" type="primary">选择指定人员</el-button> | ||||
|               </ai-wechat-selecter> | ||||
|             </div> | ||||
|           </el-step> | ||||
|         </el-steps> | ||||
|       </template> | ||||
|     </ai-card> | ||||
|     <el-dialog :title="titleType" class="editStyle" :visible.sync="isAddStep" width="575px" height="380px" | ||||
|                :close-on-click-modal="false"> | ||||
|       <el-form :model="nodeObj" label-width="120px" ref="addForm" :rules="addRules"> | ||||
|         <el-form-item label="审批步骤名称:" prop="nodeName"> | ||||
|           <el-input size="small" v-model="nodeObj.nodeName" placeholder="如:部门主管审批(限10个字)" :maxLength="10" | ||||
|                     clearable></el-input> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="审批方式:" prop="nodeType"> | ||||
|           <el-radio-group v-model="nodeObj.nodeType"> | ||||
|             <section style="position: relative;top: 10px;margin-bottom: 30px;"> | ||||
|               <el-radio :label="2">或签 | ||||
|                 <el-popover | ||||
|                     placement="top-start" | ||||
|                     width="200" | ||||
|                     trigger="click" | ||||
|                     content="或签是指该节点指定多名负责人审批时,其中任何一人完成审批即可。适合一个事项只需要某个岗位任何一人审批即可的业务场景。"> | ||||
|                   <el-button class="el-icon-warning" slot="reference" | ||||
|                              style="padding:0;height:14px;border:0;"></el-button> | ||||
|                 </el-popover> | ||||
|               </el-radio> | ||||
|               <el-radio :label="3">抄送 | ||||
|                 <el-popover | ||||
|                     placement="top-start" | ||||
|                     width="200" | ||||
|                     trigger="click" | ||||
|                     content="抄送是指一个事项审批完成后,抄送给需要知晓的单位或个人,被抄送的对象可以查阅该事项内容,无需审批。适合一个事项无需对方审批,但审批完成后需要通知对方知晓的业务场景。"> | ||||
|                   <el-button class="el-icon-warning" slot="reference" | ||||
|                              style="padding:0;height:14px;border:0;"></el-button> | ||||
|                 </el-popover> | ||||
|               </el-radio> | ||||
|             </section> | ||||
|           </el-radio-group> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|       <div slot="footer" style="text-align: center;"> | ||||
|         <el-button style="width: 92px;" size="small" @click="isAddStep = false">取消</el-button> | ||||
|         <el-button style="width: 92px;" size="small" type="primary" @click="saveAddProgress('addForm')">确认 | ||||
|         </el-button> | ||||
|       </div> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "processApproval", | ||||
|   inject: ['config'], | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     approvalSteps: String | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       form: { | ||||
|         processNodeList: [], | ||||
|       }, | ||||
|       areaId: "", | ||||
|       isAddStep: false, | ||||
|       isSelectImg: false, | ||||
|       isSelectUnit: false, | ||||
|       isSelectPerson: false, | ||||
|       nodeObj: { | ||||
|         candidateApproverType: '1', | ||||
|         candidateList: [], | ||||
|         nodeIndex: '', | ||||
|         nodeName: '', | ||||
|         nodeType: '', | ||||
|         scopeCandidates: '' | ||||
|       }, | ||||
|       indexType: '', | ||||
|       titleType: '', | ||||
|       bomIndex: '', | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     addRules() { | ||||
|       return { | ||||
|         nodeName: [ | ||||
|           {required: true, message: '请输入审批节点名称', trigger: 'change'} | ||||
|         ], | ||||
|         nodeType: [ | ||||
|           {required: true, message: '请选择审批方式', trigger: 'change'} | ||||
|         ], | ||||
|         candidateApproverType: [ | ||||
|           {required: true, message: '请选择选人方式', trigger: 'change'} | ||||
|         ], | ||||
|         scopeCandidates: [ | ||||
|           {required: true, message: '请选择选人范围', trigger: 'change'} | ||||
|         ] | ||||
|       } | ||||
|     }, | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|   methods: { | ||||
|     handleProcessApproval() { | ||||
|       return Promise.resolve(this.form) | ||||
|     }, | ||||
|     /** | ||||
|      *删除 | ||||
|      * */ | ||||
|     deleteInfo(index) { | ||||
|       this.$confirm("是否删除").then(() => { | ||||
|         this.form.processNodeList.splice(index, 1) | ||||
|       }) | ||||
|     }, | ||||
|     /** | ||||
|      * 添加流程 | ||||
|      * @param index | ||||
|      * @param item | ||||
|      * @param i | ||||
|      */ | ||||
|     addAppStep(index, item, i) { | ||||
|       this.isAddStep = true; | ||||
|       this.bomIndex = i; | ||||
|       this.indexType = index; | ||||
|       if (index == 2) { | ||||
|         this.titleType = '编辑审批步骤'; | ||||
|         item.nodeType = item.nodeType * 1; | ||||
|         item.candidateApproverType = item.candidateApproverType * 1; | ||||
|         item.scopeCandidates = item.scopeCandidates * 1; | ||||
|         this.nodeObj = JSON.parse(JSON.stringify(item)); | ||||
|       } else { | ||||
|         this.titleType = '添加审批步骤'; | ||||
|         if (this.form.processNodeList.length > 0) { | ||||
|           this.init(); | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     // 确定添加审批步骤 | ||||
|     saveAddProgress(formName) { | ||||
|       this.$refs[formName].validate((valid) => { | ||||
|         if (valid) { | ||||
|           if (this.nodeObj.scopeCandidates == 0) this.nodeObj.candidateList = []; | ||||
|           if (this.indexType == 1) { | ||||
|             this.form.processNodeList.push(JSON.parse(JSON.stringify(this.nodeObj))); | ||||
|           } else { | ||||
|             this.form.processNodeList.splice(this.bomIndex, 1, JSON.parse(JSON.stringify(this.nodeObj))); | ||||
|           } | ||||
|           this.$refs[formName].resetFields(); | ||||
|           this.isAddStep = false; | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     init() { | ||||
|       this.nodeObj = { | ||||
|         candidateApproverType: '1', | ||||
|         candidateList: [], | ||||
|         nodeIndex: '', | ||||
|         nodeName: '', | ||||
|         nodeType: '', | ||||
|         scopeCandidates: '' | ||||
|       }; | ||||
|       this.$refs['addForm'].resetFields(); | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.areaId = this.user.info.areaId.substring(0, 6) + '000000' | ||||
|     if (this.config.detailObj?.id) { | ||||
|  | ||||
|       Object.keys(this.form).map(e => this.form[e] = this.config.detailObj[e]) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .process-approval { | ||||
|   .rightBtn { | ||||
|     font-size: 14px; | ||||
|     color: #5088FF; | ||||
|     user-select: none; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|  | ||||
|   .step_title { | ||||
|     font-weight: 700; | ||||
|     height: 32px; | ||||
|     line-height: 32px; | ||||
|     display: flex; | ||||
|     padding: 0 8px; | ||||
|     justify-content: space-between; | ||||
|     color: #333; | ||||
|  | ||||
|     p { | ||||
|       font-size: 14px; | ||||
|     } | ||||
|  | ||||
|     div { | ||||
|       span { | ||||
|         margin-left: 16px; | ||||
|         font-size: 12px; | ||||
|         cursor: pointer; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .step_desc { | ||||
|     font-size: 14px; | ||||
|     padding: 8px; | ||||
|     color: #999; | ||||
|     margin-bottom: 20px; | ||||
|  | ||||
|     .desc_style { | ||||
|       display: flex; | ||||
|       margin-bottom: 16px; | ||||
|  | ||||
|       p { | ||||
|         margin-right: 80px; | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         color: #333; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .desc_person { | ||||
|       display: flex; | ||||
|       margin-bottom: 12px; | ||||
|  | ||||
|       .desc_p { | ||||
|         position: relative; | ||||
|         top: 4px; | ||||
|         width: 70px; | ||||
|       } | ||||
|  | ||||
|       .desc_div { | ||||
|         flex: 1; | ||||
|       } | ||||
|  | ||||
|       .el-tag { | ||||
|         margin-right: 8px; | ||||
|         margin-bottom: 8px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .add_btn { | ||||
|     position: absolute; | ||||
|     bottom: 0; | ||||
|     left: 0; | ||||
|     height: 64px; | ||||
|     line-height: 64px; | ||||
|     background: #F3F6F9; | ||||
|     width: 100%; | ||||
|     text-align: center; | ||||
|  | ||||
|     .el-button { | ||||
|       width: 92px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .select_per { | ||||
|     width: 640px; | ||||
|     height: 400px; | ||||
|     box-sizing: border-box; | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     margin: auto; | ||||
|  | ||||
|     .add_item { | ||||
|       width: 310px; | ||||
|       height: 400px; | ||||
|       background: rgba(252, 252, 252, 1); | ||||
|       border-radius: 2px; | ||||
|       border: 1px solid rgba(208, 212, 220, 1); | ||||
|       position: relative; | ||||
|       overflow: auto; | ||||
|  | ||||
|       .add_top { | ||||
|         width: 100%; | ||||
|         height: 40px; | ||||
|         background: rgba(245, 245, 245, 1); | ||||
|         border-bottom: 1px solid rgba(208, 212, 220, 1); | ||||
|         padding: 0 8px; | ||||
|         box-sizing: border-box; | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         align-items: center; | ||||
|       } | ||||
|  | ||||
|       .tree_list { | ||||
|         width: 100%; | ||||
|         height: 360px; | ||||
|         overflow: auto; | ||||
|       } | ||||
|  | ||||
|       .add_buttom { | ||||
|         position: absolute; | ||||
|         left: 0; | ||||
|         bottom: 0; | ||||
|         font-size: 12px; | ||||
|         width: 310px; | ||||
|         height: 32px; | ||||
|         line-height: 32px; | ||||
|         z-index: 10000; | ||||
|         background: rgba(245, 246, 247, 1); | ||||
|         color: rgba(51, 51, 51, 1); | ||||
|         box-shadow: 0px 1px 0px 0px rgba(216, 220, 227, 1); | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
|         cursor: pointer; | ||||
|       } | ||||
|  | ||||
|       .add_tag { | ||||
|         width: 310px; | ||||
|         height: 360px; | ||||
|         overflow-y: auto; | ||||
|  | ||||
|         .el-tag { | ||||
|           margin: 8px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .icon { | ||||
|     width: 48px; | ||||
|     height: 48px; | ||||
|     border: 1px solid #ddd; | ||||
|     border-radius: 4px; | ||||
|     margin-right: 16px; | ||||
|     margin-bottom: 16px; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|  | ||||
|   .icon_style { | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; | ||||
|  | ||||
|     .icon:hover { | ||||
|       border-color: #5088FF; | ||||
|     } | ||||
|  | ||||
|     .icon_color { | ||||
|       border-color: #5088FF; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .dia_per_content { | ||||
|     width: 640px; | ||||
|     height: 400px; | ||||
|     box-sizing: border-box; | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     margin: auto; | ||||
|  | ||||
|     .add_item { | ||||
|       width: 310px; | ||||
|       height: 400px; | ||||
|       background: rgba(252, 252, 252, 1); | ||||
|       border-radius: 2px; | ||||
|       border: 1px solid rgba(208, 212, 220, 1); | ||||
|       position: relative; | ||||
|       overflow: auto; | ||||
|  | ||||
|       .add_top { | ||||
|         width: 100%; | ||||
|         height: 40px; | ||||
|         background: rgba(245, 245, 245, 1); | ||||
|         border-bottom: 1px solid rgba(208, 212, 220, 1); | ||||
|         padding: 0 8px; | ||||
|         box-sizing: border-box; | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         align-items: center; | ||||
|       } | ||||
|  | ||||
|       .tree_list { | ||||
|         width: 100%; | ||||
|         height: 360px; | ||||
|         overflow: auto; | ||||
|       } | ||||
|  | ||||
|       .add_buttom { | ||||
|         position: absolute; | ||||
|         left: 0; | ||||
|         bottom: 0; | ||||
|         font-size: 12px; | ||||
|         width: 310px; | ||||
|         height: 32px; | ||||
|         line-height: 32px; | ||||
|         z-index: 10000; | ||||
|         background: rgba(245, 246, 247, 1); | ||||
|         color: rgba(51, 51, 51, 1); | ||||
|         box-shadow: 0px 1px 0px 0px rgba(216, 220, 227, 1); | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
|         cursor: pointer; | ||||
|       } | ||||
|  | ||||
|       .add_tag { | ||||
|         width: 310px; | ||||
|         height: 360px; | ||||
|         overflow-y: auto; | ||||
|  | ||||
|         .el-tag { | ||||
|           margin: 8px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .peraoBtn { | ||||
|     .el-button--text { | ||||
|       color: #333; | ||||
|       font-size: 12px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep .el-step__icon.is-text { | ||||
|     border: 2px solid #2266FF; | ||||
|     background: #2266FF; | ||||
|     color: #FFFFFF; | ||||
|   } | ||||
|  | ||||
|   ::v-deep .el-step__line { | ||||
|     background-color: #D0D4DC; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,365 @@ | ||||
| <template> | ||||
|   <section class="personal-signature"> | ||||
|     <ai-list v-if="!showPhonePage"> | ||||
|       <ai-title slot="title" title="个人签名" :isShowBottomBorder="false"/> | ||||
|       <template #custom> | ||||
|         <div class="signaturePane"> | ||||
|           <div class="signatureCard" v-for="(op,i) in signatures" :key="i"> | ||||
|             <div class="default" v-if="op.isDefault==1">默认</div> | ||||
|             <div class="body"> | ||||
|               <el-image :src="`data:image/png;base64,${op.signSealData}`"/> | ||||
|             </div> | ||||
|             <div class="footer"> | ||||
|               <el-button type="text" :disabled="op.isDefault==1" @click.stop="handleSetDefault(op.id)">设为默认</el-button> | ||||
|               <hr/> | ||||
|               <el-button type="text" :disabled="op.isDefault==1||op.signType>0" @click.stop="handleDelete(op.id)">删除 | ||||
|               </el-button> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="signatureCard add" @click="dialog=true"> | ||||
|             <ai-icon icon="iconAdd" size="32px"/> | ||||
|             <span>点击添加签名</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <ai-dialog :visible.sync="dialog" v-bind="dialogConf" @onConfirm="handleSubmit" | ||||
|                @closed="form={},drawPlaceholder=true,qrCode=null,showQRCode=false,getSignatures()"> | ||||
|       <ai-drawer v-if="hasAuthed" :seal.sync="sealData" ref="aiDrawer"> | ||||
|         <template #tools> | ||||
|           <el-popover trigger="manual" v-model="showQRCode"> | ||||
|             <el-image :src="qrCode"/> | ||||
|             <div class="writeInPhone" slot="reference" @click.stop="showQR"> | ||||
|               <ai-icon icon="iconEwm"/> | ||||
|               <span>手机签名</span> | ||||
|             </div> | ||||
|           </el-popover> | ||||
|         </template> | ||||
|       </ai-drawer> | ||||
|       <el-form size="small" :model="form" ref="authForm" :rules="rules" class="authZone" v-else label-suffix=":" | ||||
|                label-width="100px"> | ||||
|         <el-alert type="warning" title="第一次添加个人签名,需先进行实名认证" show-icon :closable="false"/> | ||||
|         <el-form-item label="姓名" prop="personName"> | ||||
|           <el-input v-model="form.personName" clearable placeholder="姓名"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="身份证号" prop="idNumber"> | ||||
|           <el-input v-model="form.idNumber" clearable placeholder="身份证号"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="手机号码" prop="signPhone"> | ||||
|           <el-input v-model="form.signPhone" clearable placeholder="手机号码"/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|     <draw-in-phone v-if="showPhonePage"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
| import DrawInPhone from "./drawInPhone"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppPersonalSignature", | ||||
|   label: "个人签名", | ||||
|   components: {DrawInPhone}, | ||||
|   provide() { | ||||
|     return { | ||||
|       signature: this | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     hasAuthed() { | ||||
|       return this.signatures.length > 0 | ||||
|     }, | ||||
|     dialogConf() { | ||||
|       return this.hasAuthed ? { | ||||
|         title: "手写签名", | ||||
|         width: '720px' | ||||
|       } : { | ||||
|         title: "实名认证", | ||||
|         width: '520px' | ||||
|       } | ||||
|     }, | ||||
|     rules() { | ||||
|       return { | ||||
|         personName: [{required: true, message: "请填写姓名"}], | ||||
|         signPhone: [ | ||||
|           {required: true, message: "请填写手机号码"}, | ||||
|           {pattern: /^1[3456789]\d{9}$/, message: "手机号码格式有误"} | ||||
|         ], | ||||
|         idNumber: [ | ||||
|           {required: true, message: "请填写身份证号码"}, | ||||
|           {validator: (r, v, cb) => cb(this.idCardNoUtil.checkIdCardNo(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; | ||||
|  | ||||
|   ::v-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); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   ::v-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; | ||||
|     } | ||||
|   } | ||||
|   ::v-deep .ai-dialog__wrapper { | ||||
|     .ai-dialog__content--wrapper { | ||||
|       padding-right: 0 !important; | ||||
|     } | ||||
|  | ||||
|     .el-dialog__body { | ||||
|       padding: 24px 0; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     .authZone { | ||||
|       padding: 0 16px 24px; | ||||
|       width: 100%; | ||||
|       box-sizing: border-box; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       gap: 24px; | ||||
|  | ||||
|       .el-alert { | ||||
|         border: 1px solid #FF8822; | ||||
|       } | ||||
|  | ||||
|       .el-form-item { | ||||
|         margin-bottom: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,110 @@ | ||||
| <template> | ||||
|   <section class="drawInPhone" @touchmove.prevent> | ||||
|     <div class="endPage" v-if="finished">操作结束请关闭页面</div> | ||||
|     <ai-drawer :seal.sync="sealData" placeholder="请签名" :width="device.width" :height="device.height"> | ||||
|       <template #tools> | ||||
|         <div class="writeInPhone" slot="reference" @click.stop="handleSubmit"> | ||||
|           <ai-icon icon="iconPublish"/> | ||||
|           <span>提交</span> | ||||
|         </div> | ||||
|       </template> | ||||
|     </ai-drawer> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "drawInPhone", | ||||
|   inject: ['signature'], | ||||
|   data() { | ||||
|     return { | ||||
|       sealData: null, | ||||
|       device: {width: 0, height: 0}, | ||||
|       finished: false | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.device.width = document.body.clientWidth | ||||
|     this.device.height = document.body.clientHeight | ||||
|     window.onresize = () => { | ||||
|       this.device.width = document.body.clientWidth | ||||
|       this.device.height = document.body.clientHeight | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleSubmit() { | ||||
|       let sealData = this.sealData?.replace(/data:image\/png;base64,/, ''), | ||||
|           {userId} = this.$route.query | ||||
|       if (!userId) return alert("缺少必要参数") | ||||
|       sealData && this.signature.instance({ | ||||
|         url: '/app/syssignaccount/upload-sealdata', | ||||
|         headers: {"Content-Type": "application/json"}, | ||||
|         method: 'post', | ||||
|         params: {userId}, | ||||
|         data: sealData, | ||||
|         withoutToken: true | ||||
|       }).then(res => { | ||||
|         if (res?.code == 0) { | ||||
|           alert("添加成功!") | ||||
|           this.finished = true | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .drawInPhone { | ||||
|   position: fixed; | ||||
|   left: 0; | ||||
|   right: 0; | ||||
|   top: 0; | ||||
|   bottom: 0; | ||||
|   z-index: 20210205932; | ||||
|  | ||||
|   .endPage { | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     top: 0; | ||||
|     bottom: 0; | ||||
|     z-index: 20210205933; | ||||
|     background: rgba(#000, .8); | ||||
|     color: #999; | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     font-size: 32px; | ||||
|   } | ||||
|  | ||||
|   .AiDrawer { | ||||
|     margin: 0; | ||||
|   } | ||||
|  | ||||
|   .writeInPhone { | ||||
|     position: absolute; | ||||
|     width: 72px; | ||||
|     height: 32px; | ||||
|     background: rgba(#000, .5); | ||||
|     border-radius: 16px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     gap: 4px; | ||||
|     color: rgba(#fff, .6); | ||||
|     cursor: pointer; | ||||
|     left: 16px; | ||||
|     top: 16px; | ||||
|  | ||||
|     .AiIcon { | ||||
|       width: auto; | ||||
|       height: auto; | ||||
|     } | ||||
|  | ||||
|     &:hover { | ||||
|       color: #fff; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
		Reference in New Issue
	
	Block a user