Ver Fonte

Merge branch 'v2.0_ht' into master_ht

yujinwen há 5 meses atrás
pai
commit
173a1fbd50

+ 6 - 0
src/api/riskLevel/index.js

@@ -0,0 +1,6 @@
+import apiRiskLevelRelationShip from './relationShip'
+import apiRiskLevelProduct from './product'
+export {
+  apiRiskLevelRelationShip,
+  apiRiskLevelProduct
+}

+ 12 - 0
src/api/riskLevel/product.js

@@ -0,0 +1,12 @@
+import { get, post } from "@/api/index";
+
+export default {
+  // 品种列表
+  permissionList:()=>{
+    return get('/chart_permission/list',{})
+  },
+  // 客户风险等级选项
+  setRiskLevel:params=>{
+    return post('/chart_permission/setRiskLevel',params)
+  },
+}

+ 28 - 0
src/api/riskLevel/relationShip.js

@@ -0,0 +1,28 @@
+import { get, post } from "@/api/index";
+
+export default {
+  // 风险等级关联关系列表
+  relationList:params=>{
+    return get('/customer/mappingList',params)
+  },
+  // 客户风险等级选项
+  userRiskLevelOpts:()=>{
+    return get('/risk/customerRiskList',{})
+  },
+  // 产品风险等级选项
+  productRiskLevelOpts:()=>{
+    return get('/risk/productRiskList',{})
+  },
+  // 新增关联关系
+  relationAdd:params=>{
+    return post('/customer/addMapping',params)
+  },
+  // 编辑关联关系
+  relationEdit:params=>{
+    return post('/customer/editMapping',params)
+  },
+  // 删除关联关系
+  relationDel:params=>{
+    return post('/customer/deleteMapping',params)
+  },
+}

+ 4 - 0
src/assets/svg/menu/risklevel.svg

@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.99 19.7904C9.88 19.7904 9.78 19.7604 9.69001 19.7004C7.26 18.2304 5.5 17.0104 4.2 15.4404C2.7 13.6404 1.97 11.5404 1.89 8.84043V8.79043C1.89 8.64043 1.88 8.50043 1.88 8.36043C1.88 8.22043 1.88 8.07043 1.89 7.93043V5.15043C1.89 4.83043 2.15 4.56043 2.48 4.56043C5.37 4.56043 8.05 3.00043 9.48 0.49043C9.58 0.31043 9.78 0.19043 9.99 0.19043C10.2 0.19043 10.4 0.30043 10.5 0.49043C11.93 3.00043 14.62 4.56043 17.51 4.56043C17.83 4.56043 18.1 4.82043 18.1 5.15043V8.84043C18.1 8.88043 18.1 8.92043 18.09 8.95043C17.89 14.6704 14.73 17.0204 10.3 19.7104C10.2 19.7604 10.1 19.7904 9.99 19.7904ZM3.07001 8.82043C3.14001 11.2404 3.79 13.1004 5.11 14.6904C6.25 16.0704 7.84001 17.1904 10 18.5104C14.1 16.0104 16.78 13.9004 16.93 8.81043C16.93 8.78043 16.93 8.76043 16.94 8.73043V5.71043C14.17 5.53043 11.62 4.11043 10.01 1.86043C8.38001 4.11043 5.83 5.53043 3.07001 5.71043V7.95043C3.07001 8.09043 3.06 8.23043 3.06 8.36043C3.06 8.50043 3.06001 8.63043 3.07001 8.77043V8.82043Z" fill="currentColor"/>
+<path d="M10.21 15.11C10.14 15.11 10.07 15.1 9.99996 15.07C9.69996 14.95 9.54996 14.61 9.65996 14.31L10.99 10.88H8.56996C8.37996 10.88 8.19996 10.79 8.08996 10.63C7.97996 10.47 7.94996 10.27 8.01996 10.09L9.43996 6.09001C9.54996 5.78001 9.87996 5.62001 10.19 5.73001C10.5 5.84001 10.66 6.17001 10.55 6.48001L9.39996 9.71001H11.85C12.04 9.71001 12.23 9.81001 12.33 9.97001C12.44 10.13 12.46 10.33 12.39 10.51L10.75 14.74C10.67 14.97 10.45 15.11 10.21 15.11Z" fill="currentColor"/>
+</svg>

+ 1 - 1
src/layout/Index.vue

@@ -28,7 +28,7 @@ getPermissionData()
 .layout-wrap {
   min-height: 100%;
   padding-top: 48px;
-  padding-left: 180px;
+  padding-left: 200px;
   transition: all .3s;
   .layout-content {
     padding: 30px;

+ 3 - 2
src/layout/components/LeftWrap.vue

@@ -108,7 +108,8 @@ function getMenuIcon(item){
         '/customer/notification':'menu/message',
         '/mediaMgt/pictureLib':'menu/piclib',
         '/customer/feedbackList':'menu/feedback',
-        '/system':'menu/setting'
+        '/system':'menu/setting',
+        '/riskLevel':'menu/risklevel'
     }
     return iconMap[item]||'menu/setting'
 
@@ -174,7 +175,7 @@ function getMenuIcon(item){
   --el-menu-text-color: #333;
   --el-menu-active-color: #086CE0;
   --el-menu-item-font-size:16px;
-  width: 180px;
+  width: 200px;
   z-index: 50;
   position: fixed;
   top: 48px;

+ 31 - 0
src/router/modules/riskLevel.js

@@ -0,0 +1,31 @@
+import LayoutIndex from '@/layout/Index.vue'
+
+export default[
+  {
+    path:'/riskLevel',
+    component:LayoutIndex,
+    name:'RiskLevel',
+    meta:{
+      title:'风险等级配置'
+    },
+    children:[
+      {
+        path:'product',
+        component:()=>import('@/views/riskLevel/product/Index.vue'),
+        name:"RiskLevelProduct",
+        meta:{
+          title:'产品风险等级配置'
+        },
+      },
+      {
+        path:'relationShip',
+        component:()=>import('@/views/riskLevel/RelationShip/Index.vue'),
+        name:"RiskLevelRelationShip",
+        meta:{
+          title:'关联关系配置'
+        },
+      },
+    ]
+  }
+]
+

+ 111 - 0
src/views/riskLevel/RelationShip/Index.vue

@@ -0,0 +1,111 @@
+<script setup>
+import { apiRiskLevelRelationShip } from '@/api/riskLevel'
+import EditRelation from './components/EditRelation.vue'
+
+const tableColOpts = [
+  {
+    label: '用户风险等级',
+    key: 'CustomerRisk',
+  },
+  {
+    label: '产品风险等级',
+    key: 'ProductRisk',
+  },
+  {
+    label: '创建人',
+    key: 'Creator',
+  },
+  {
+    label: '更新时间',
+    key: 'UpdatedTime',
+    sort: true
+  },
+]
+const list = ref([])
+const tableLoading = ref(false)
+let sortType=''
+async function getList() {
+  tableLoading.value = true
+  const res = await apiRiskLevelRelationShip.relationList({
+    Sort:sortType
+  })
+  tableLoading.value = false
+  list.value = res.Data.List || []
+}
+getList()
+
+function handleTableSort(e) {
+  const { order, prop } = e//order:"descending",prop: "RegisterTime"
+  sortType=order === 'descending' ? 'desc' : 'asc'
+  getList()
+}
+
+
+
+const showEditRelation = ref(false)
+const editData = ref(null)
+function handleEdit(e){
+  editData.value=e
+  showEditRelation.value=true
+}
+
+
+async function handleDel(e) {
+  await ElMessageBox.confirm('删除后不可恢复,是否确认删除?', '提示', {
+    type: 'warning',
+  })
+  const res = await apiRiskLevelRelationShip.relationDel({
+    CustomerRisk: e.CustomerRisk
+  })
+  if (res.Ret !== 200) return
+  ElMessage.success('删除成功');
+  getList()
+}
+</script>
+
+<template>
+  <div>
+    <el-button
+      type="primary"
+      @click="
+        showEditRelation = true;
+        editData = null;
+      "
+      >添加关联关系</el-button
+    >
+    <div class="list-wrap" style="margin-top: 20px">
+      <el-table
+        :data="list"
+        border
+        stripe
+        element-loading-text="数据加载中..."
+        v-loading="tableLoading"
+        @sort-change="handleTableSort"
+      >
+        <el-table-column
+          v-for="column in tableColOpts"
+          :key="column.key"
+          :prop="column.key"
+          :label="column.label"
+          :sortable="column.sort ? 'custom' : false"
+        >
+        </el-table-column>
+        <el-table-column label="操作" width="160">
+          <template #default="{ row }">
+            <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
+            <!-- <el-button type="danger" link @click="handleDel(row)"
+              >删除</el-button
+            > -->
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+
+  <!-- 添加/编辑关联关系 -->
+  <EditRelation 
+    v-model:show="showEditRelation" 
+    :editData="editData"
+    @success="getList"
+  />
+</template>

+ 140 - 0
src/views/riskLevel/RelationShip/components/EditRelation.vue

@@ -0,0 +1,140 @@
+<script setup>
+import { apiRiskLevelRelationShip } from '@/api/riskLevel'
+
+const show = defineModel('show', { type: Boolean, default: false })
+
+const props = defineProps({
+  editData: {
+    type: [Object, null],
+    default: null
+  }
+})
+const emits=defineEmits(['success'])
+
+watch(
+  ()=>show.value,
+  (n)=>{
+    if(n&&props.editData){
+      formState.userLevel=props.editData.CustomerRisk
+      formState.productLevel=props.editData.ProductRisk
+    }
+  }
+)
+
+// 用户风险等级选项
+const userRiskLevelOpts = ref([])
+async function getUserRiskLevelOpts() {
+  const res = await apiRiskLevelRelationShip.userRiskLevelOpts()
+  if (res.Ret === 200) {
+    userRiskLevelOpts.value = res.Data.List || []
+  }
+}
+getUserRiskLevelOpts()
+
+// 产品风险等级选项
+let productLevelOpts=[]
+async function getProductRiskLevelOpts() {
+  const res = await apiRiskLevelRelationShip.productRiskLevelOpts()
+  if (res.Ret === 200) {
+    const arr = res.Data.List || []
+    productLevelOpts=arr.map(item=>{
+      return {
+        ...item,
+        value:item.RiskName
+      }
+    })
+  }
+}
+getProductRiskLevelOpts()
+
+const formRef=ref(null)
+const formRules = {
+  userLevel: [{ required: true, message: '请选择用户风险等级', trigger: 'blur' },],
+  productLevel: [
+    { required: true, message: '请选择产品风险等级', trigger: 'blur' },
+    {
+      validator: (rule, value, callback) => {
+        const regex = /^R\d+$/;
+        if (!regex.test(value)) {
+          callback(new Error('输入的值必须是 R 加数字,并且不能包含空格'));
+        } else {
+          callback();
+        }
+      },
+      trigger: 'blur'
+    }
+  ]
+}
+const formState = reactive({
+  userLevel: '',
+  productLevel: ''
+})
+
+function querySearch(queryString, cb) {
+  const validLevels = productLevelOpts; // 可用的选项
+  cb(validLevels)
+}
+
+async function handleSave() {
+  await formRef.value.validate()
+  const params={
+    CustomerRisk:formState.userLevel,
+    ProductRisk:formState.productLevel
+  }
+  const res=props.editData?await apiRiskLevelRelationShip.relationEdit(params) : await apiRiskLevelRelationShip.relationAdd(params)
+  if(res.Ret!==200) return
+  ElMessage.success(props.editData?'编辑成功': '添加成功');
+  show.value=false
+  emits('success')
+}
+
+</script>
+
+<template>
+  <el-dialog
+    v-model="show"
+    width="500"
+    :title="editData ? '编辑' : '添加关联关系'"
+    draggable
+  >
+    <el-form
+      ref="formRef"
+      :model="formState"
+      :rules="formRules"
+      class="form-box"
+      label-width="130px"
+      hide-required-asterisk
+    >
+      <el-form-item prop="userLevel" label="用户风险等级">
+        <el-select
+          v-model="formState.userLevel"
+          placeholder="请选择用户风险等级"
+        >
+          <el-option
+            v-for="item in userRiskLevelOpts"
+            :key="item.Id"
+            :label="item.RiskName"
+            :value="item.RiskName"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="productLevel" label="产品最高风险等级">
+        <el-autocomplete
+          v-model="formState.productLevel"
+          :fetch-suggestions="querySearch"
+          placeholder="请选择产品风险等级"
+        />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="footer-wrap">
+        <el-button type="primary" plain size="large" @click="show = false"
+          >取消</el-button
+        >
+        <el-button type="primary" size="large" @click="handleSave"
+          >保存</el-button
+        >
+      </div>
+    </template>
+  </el-dialog>
+</template>

+ 59 - 0
src/views/riskLevel/product/Index.vue

@@ -0,0 +1,59 @@
+<script setup>
+import { apiRiskLevelProduct } from '@/api/riskLevel'
+import SetRisk from './components/SetRisk.vue'
+
+const list = ref(null)
+function getList() {
+  apiRiskLevelProduct.permissionList().then(res => {
+    if (res.Ret === 200) {
+      list.value = res.Data.List || []
+    }
+  })
+}
+getList()
+
+const showSetRisk=ref(false)
+const editData=ref(null)
+function handleShowSetRisk(e){
+  editData.value={
+    ...e.data,
+    parentLabel:`${e.parent.data.name}/${e.data.name}`
+  }
+  showSetRisk.value=true
+}
+</script>
+
+<template>
+  <el-tree class="permission-list" :data="list">
+    <template #default="{ node, data }">
+      <span class="permission-list-item">
+        <span>{{ data.name }}</span>
+        <el-tag type="warning" v-if="data.riskLevel&&node.level>1" style="margin-left:10px">{{data.riskLevel}}</el-tag>
+        <el-button type="primary" link style="float:right" v-if="node.level>1" @click="handleShowSetRisk(node)">设置风险等级</el-button>
+      </span>
+    </template>
+  </el-tree>
+
+  <!-- 设置风险等级 -->
+  <SetRisk 
+    v-model:show="showSetRisk" 
+    :editData="editData"
+    @success="getList"
+  />
+</template>
+
+<style lang="scss" scoped>
+.permission-list{
+  padding: 20px;
+  :deep(.el-tree-node__content){
+    width: 100%;
+    height: fit-content;
+    padding-top: 10px;
+    padding-bottom: 10px;
+    border-bottom: 1px solid #c8cdd9;
+  }
+  .permission-list-item{
+    flex: 1;
+  }
+}
+</style>

+ 118 - 0
src/views/riskLevel/product/components/SetRisk.vue

@@ -0,0 +1,118 @@
+<script setup>
+import { apiRiskLevelRelationShip,apiRiskLevelProduct } from '@/api/riskLevel'
+
+const show = defineModel('show', { type: Boolean, default: false })
+
+const props = defineProps({
+  editData: {
+    type: [Object, null],
+    default: null
+  }
+})
+const emits=defineEmits(['success'])
+
+watch(
+  ()=>show.value,
+  (n)=>{
+    if(n&&props.editData){
+      formState.riskLevel=props.editData.riskLevel
+    }
+  }
+)
+
+
+// 产品风险等级选项
+let productLevelOpts=[]
+async function getProductRiskLevelOpts() {
+  const res = await apiRiskLevelRelationShip.productRiskLevelOpts()
+  if (res.Ret === 200) {
+    const arr = res.Data.List || []
+    productLevelOpts=arr.map(item=>{
+      return {
+        ...item,
+        value:item.RiskName
+      }
+    })
+  }
+}
+getProductRiskLevelOpts()
+
+const formRef=ref(null)
+const formRules = {
+  riskLevel: [
+    { required: true, message: '请选择产品风险等级', trigger: 'blur' },
+    {
+      validator: (rule, value, callback) => {
+        const regex = /^R\d+$/;
+        if (!regex.test(value)) {
+          callback(new Error('输入的值必须是 R 加数字,并且不能包含空格'));
+        } else {
+          callback();
+        }
+      },
+      trigger: 'blur'
+    }
+  ]
+}
+const formState = reactive({
+  riskLevel: ''
+})
+
+function querySearch(queryString, cb) {
+  const validLevels = productLevelOpts; // 可用的选项
+  cb(validLevels)
+}
+
+async function handleSave() {
+  await formRef.value.validate()
+  const params={
+    Id:props.editData.id,
+    RiskLevel:formState.riskLevel
+  }
+  const res=await apiRiskLevelProduct.setRiskLevel(params)
+  if(res.Ret!==200) return
+  ElMessage.success('设置成功');
+  show.value=false
+  emits('success')
+}
+
+</script>
+
+<template>
+  <el-dialog
+    v-model="show"
+    width="500"
+    title="设置风险等级 "
+    draggable
+  >
+    <el-form
+      ref="formRef"
+      :model="formState"
+      :rules="formRules"
+      class="form-box"
+      label-width="80px"
+      hide-required-asterisk
+    >
+      <el-form-item prop="permission" label="品种">
+        <span>{{props.editData.parentLabel}}</span>
+      </el-form-item>
+      <el-form-item prop="riskLevel" label="风险等级">
+        <el-autocomplete
+          v-model="formState.riskLevel"
+          :fetch-suggestions="querySearch"
+          placeholder="请选择产品风险等级"
+        />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="footer-wrap">
+        <el-button type="primary" plain size="large" @click="show = false"
+          >取消</el-button
+        >
+        <el-button type="primary" size="large" @click="handleSave"
+          >保存</el-button
+        >
+      </div>
+    </template>
+  </el-dialog>
+</template>