初始化角色管理功能
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/service/OperatorDetailService.java b/backend/src/main/java/com/supwisdom/dlpay/framework/service/OperatorDetailService.java
index eebda6d..652e3d7 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/framework/service/OperatorDetailService.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/service/OperatorDetailService.java
@@ -3,6 +3,7 @@
 import com.supwisdom.dlpay.framework.domain.TOperator;
 import com.supwisdom.dlpay.framework.jpa.page.Pagination;
 import com.supwisdom.dlpay.portal.bean.OperatorSearchBean;
+import com.supwisdom.dlpay.portal.bean.RoleSearchBean;
 import com.supwisdom.dlpay.portal.domain.TBResource;
 import com.supwisdom.dlpay.portal.domain.TBRole;
 import org.springframework.security.core.userdetails.UserDetailsService;
@@ -33,4 +34,7 @@
 
   @Transactional(readOnly = true)
   TBRole findRoleById(String roleId);
+
+  @Transactional(readOnly = true)
+  Pagination getRoleList(RoleSearchBean bean);
 }
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java b/backend/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java
index 6df8991..e1b9eec 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java
@@ -10,6 +10,7 @@
 import com.supwisdom.dlpay.framework.util.TradeDict;
 import com.supwisdom.dlpay.mobile.exception.PortalBusinessException;
 import com.supwisdom.dlpay.portal.bean.OperatorSearchBean;
+import com.supwisdom.dlpay.portal.bean.RoleSearchBean;
 import com.supwisdom.dlpay.portal.dao.ResourceDao;
 import com.supwisdom.dlpay.portal.dao.RoleDao;
 import com.supwisdom.dlpay.portal.domain.TBResource;
@@ -137,4 +138,9 @@
   public TBRole findRoleById(String roleId) {
     return roleDao.findById(roleId).orElse(null);
   }
+
+  @Override
+  public Pagination getRoleList(RoleSearchBean bean) {
+    return null;
+  }
 }
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
index 71aed08..fba92f8 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
@@ -1058,6 +1058,17 @@
         if(user.userid.isNullOrEmpty()){
             return JsonResult.error("用户未绑定身份")
         }
+        val cardResponse = userProxy.queryCard(QueryCardParam().apply {
+            this.userid = user.userid
+            this.cardtype = ConstantUtil.CARDTYPE_BANKCARD
+        })
+        if (cardResponse.retcode != 0) {
+            logger.error { "查询用户[${user.userid}]卡片信息失败:${cardResponse.retmsg}" }
+            return JsonResult.error(-1,"银行卡信息不存在,请重新绑定")
+        }
+        if (!cardResponse.card.signed) {
+            return JsonResult.error(-1,"请先签约银行卡")
+        }
         val qrcodeResult = userProxy.qrcode(QrcodeParam().apply {
             this.uid = user.uid
             this.userid = user.userid
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
index 35bfe6e..867748c 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
@@ -637,4 +637,21 @@
             JsonResult.error("设置管理员状态异常")
         }
     }
+
+    /**
+     * 获取角色列表
+     */
+    @RequestMapping(value = ["/role/list"], method = [RequestMethod.GET])
+    fun getOperatorList(bean: RoleSearchBean): JsonResult? {
+        return try {
+            val page = operatorDetailService.getRoleList(bean)
+            if (page.list == null || page.list.size == 0) {
+                return JsonResult.ok().put("msg", "无数据")
+            }
+            return JsonResult.ok().put("page", page)
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("查询操作员列表失败")
+        }
+    }
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/RoleSearchBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/RoleSearchBean.kt
new file mode 100644
index 0000000..3f8a560
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/RoleSearchBean.kt
@@ -0,0 +1,7 @@
+package com.supwisdom.dlpay.portal.bean
+
+class RoleSearchBean {
+    var rolename: String = ""
+    var pageno: Int = 0
+    var pagesize: Int = 10
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleDao.kt
index c5b553d..739a623 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleDao.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleDao.kt
@@ -6,4 +6,5 @@
 
 @Repository
 interface RoleDao : JpaRepository<TBRole, String>{
+
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleRepository.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleRepository.kt
new file mode 100644
index 0000000..0190202
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleRepository.kt
@@ -0,0 +1,5 @@
+package com.supwisdom.dlpay.portal.dao
+
+interface RoleRepository {
+
+}
\ No newline at end of file
diff --git a/frontend/src/api/role.js b/frontend/src/api/role.js
index 4d1a002..48f041d 100644
--- a/frontend/src/api/role.js
+++ b/frontend/src/api/role.js
@@ -7,6 +7,14 @@
   })
 }
 
+export function getRoleList(query) {
+  return request({
+    url: '/role/list',
+    method: 'get',
+    params: query
+  })
+}
+
 export function getRoutes() {
   return request({
     url: '/vue-element-admin/routes',
diff --git a/frontend/src/views/operator/index.vue b/frontend/src/views/operator/index.vue
index 64ddeb5..3f9dd44 100644
--- a/frontend/src/views/operator/index.vue
+++ b/frontend/src/views/operator/index.vue
@@ -1,5 +1,3 @@
-/* eslint-disable vue/valid-v-model */
-
 <template>
   <div class="app-container">
     <div class="filter-container">
@@ -44,7 +42,7 @@
 
     </div>
     <el-tooltip class="item" effect="dark" content="新用户密码123456" placement="top">
-      <el-button type="primary" icon="el-icon-circle-plus-outline" @click="addOperator()">新增</el-button>
+      <el-button type="primary" icon="el-icon-circle-plus-outline" @click="addOperator()">新增管理员</el-button>
     </el-tooltip>
 
     <el-table
@@ -209,7 +207,6 @@
       callback()
     }
     return {
-      ssss: true,
       formData: {
         opercode: '',
         opername: '',
diff --git a/frontend/src/views/role/index.vue b/frontend/src/views/role/index.vue
new file mode 100644
index 0000000..474ba9d
--- /dev/null
+++ b/frontend/src/views/role/index.vue
@@ -0,0 +1,118 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <div class="filter-item" style="margin-right:15px">名称</div>
+      <el-input
+        v-model="formData.rolename"
+        placeholder="角色名称"
+        style="width: 350px;margin-right:50px"
+        class="filter-item"
+      />
+      <el-button
+        style=""
+        class="filter-item"
+        type="primary"
+        icon="el-icon-search"
+        @click="handleFilter()"
+      >
+        搜索
+      </el-button>
+    </div>
+    <el-button type="primary" icon="el-icon-circle-plus-outline" @click="addRole()">新增角色</el-button>
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;margin-top:10px"
+    >
+      <el-table-column label="角色名称" width="150">
+        <template slot-scope="{row}">
+          <span>{{ row.rolename }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="角色描述" align="center">
+        <template slot-scope="{row}">
+          <span>{{ row.detail }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="修改时间" align="center" width="100">
+        <template slot-scope="{row}">
+          <span>{{ timeFormat(row.moditime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="100">
+        <template slot-scope="{row}">
+          <el-tooltip class="item" effect="dark" content="修改" placement="bottom">
+            <el-button type="primary" icon="el-icon-edit" circle size="mini" @click="updateOperator(row)" />
+          </el-tooltip>
+          <el-tooltip class="item" effect="dark" content="重置密码" placement="bottom">
+            <el-button type="warning" icon="el-icon-refresh" circle size="mini" @click="resetPassword(row)" />
+          </el-tooltip>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="formData.pageno"
+      :limit.sync="formData.pagesize"
+      style="margin-top:0;"
+      @pagination="getRoleList"
+    />
+  </div>
+</template>
+<script>
+import Pagination from '@/components/Pagination'
+import { getRoleList } from '@/api/operator'
+export default {
+  name: 'Role',
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      formData: {
+        rolename: '',
+        pageno: 1,
+        pagesize: 10
+      },
+      listLoading: false,
+      tableKey: 0,
+      list: null,
+      total: 0,
+      title: '',
+      rules: {
+
+      }
+    }
+  },
+  methods: {
+    handleFilter() {
+      this.formData.pageno = 1
+      this.getRoleList()
+    },
+    getRoleList() {
+      getRoleList(this.formData).then(response => {
+        if (response.page) {
+          this.list = response.page.liste
+          this.total = response.page.totalCount
+        } else {
+          this.list = null
+          this.total = 0
+        }
+        this.listLoading = false
+      }).catch(error => {
+        this.$message({
+          message: error.msg || '请求异常',
+          type: 'error'
+        })
+        this.listLoading = false
+      })
+    }
+  }
+}
+</script>