chenlei 1 lună în urmă
părinte
comite
c5ad641859
39 a modificat fișierele cu 1381 adăugiri și 2601 ștergeri
  1. 1 1
      index.html
  2. 24 7
      src/api/customer/modules/user.js
  3. 0 12
      src/api/report/common.js
  4. 0 9
      src/api/report/index.js
  5. 0 28
      src/api/report/pdf.js
  6. 0 24
      src/api/report/reportPush.js
  7. BIN
      src/assets/imgs/avatar.png
  8. BIN
      src/assets/imgs/login_bg.png
  9. BIN
      src/assets/imgs/login_logo.png
  10. BIN
      src/assets/imgs/logo.png
  11. 5 5
      src/components/SelectReportClassify.vue
  12. 42 38
      src/layout/components/HeaderWrap.vue
  13. 16 44
      src/layout/components/LeftWrap.vue
  14. 0 74
      src/layout/components/NoticeWrap.vue
  15. 4 1
      src/main.js
  16. 59 29
      src/router/modules/customer.js
  17. 0 22
      src/router/modules/pushapp.js
  18. 0 22
      src/router/modules/report.js
  19. 5 3
      src/router/modules/system.js
  20. 39 0
      src/utils/buttonConfig.js
  21. 19 9
      src/views/Login.vue
  22. 262 0
      src/views/customer/CompanyEdit.vue
  23. 20 138
      src/views/customer/PotentialUserList.vue
  24. 0 6
      src/views/customer/UserEdit.vue
  25. 210 195
      src/views/customer/UserList.vue
  26. 58 211
      src/views/customer/UserSearch.vue
  27. 312 0
      src/views/customer/components/ContactTable.vue
  28. 7 9
      src/views/customer/components/OperationRecord.vue
  29. 0 207
      src/views/customer/components/PermissionTable.vue
  30. 0 219
      src/views/pushReportList/components/bulkOperations.vue
  31. 0 437
      src/views/pushReportList/index.vue
  32. 0 360
      src/views/report/pdf/List.vue
  33. 0 176
      src/views/report/pdf/components/EditPdf.vue
  34. 0 47
      src/views/report/pdf/components/SelectAuthor.vue
  35. 60 48
      src/views/system/AuthSet.vue
  36. 45 34
      src/views/system/RoleList.vue
  37. 103 98
      src/views/system/userList/Index.vue
  38. 88 87
      src/views/system/userList/components/DepartWrap.vue
  39. 2 1
      vite.config.js

+ 1 - 1
index.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8" />
     <link rel="icon" type="image/x-icon" href="/fa.ico" id="icon"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>东吴CRM</title>
+    <title>金瑞CRM</title>
   </head>
   <body>
     <div id="app"></div>

+ 24 - 7
src/api/customer/modules/user.js

@@ -3,8 +3,9 @@ import { get, post } from "@/api/index";
 export default {
   //用户列表数据
   userList: params => {
-    return get("/user/list", params);
+    return get("/users/page_list", params);
   },
+  // 用户详情
   userInfo: params => {
     return get("/user/detail", params);
   },
@@ -35,24 +36,40 @@ export default {
   userDelete:params=>{
     return post('/user/delete',params)
   },
-  // 潜在用户列表
-  potentialUserList:params=>{
-    return get('/user/potential/list',params)
-  },
   //潜在用户转客户
   potentialUserEdit:params=>{
     return post('/user/potential/edit',params)
   },
   // 客户全局搜索
   userGlobalSearch:params=>{
-    return get('/user/global/list',params)
+    return get('/users/search?',params)
   },
   // 营业部门列表
   sellerDepartmentList:params=>{
-    return get('/seller/department/list',params)
+    return get('/seller/list',params)
   },
   // 导出营业部门列表
   potentialExportExcel:params=>{
     return get('/user/potential/export/excel',params)
   },
+  // 机构详情
+  companyInfo: params => {
+    return get("/company/detail", params);
+  },
+  // 新增机构
+  companyAdd: params => {
+    return post("/company/add", params);
+  },
+  // 机构修改
+  companyEdit: params => {
+    return post("/company/edit", params);
+  },
+  // 机构操作记录
+  companyOperationRecord:params=>{
+    return get('/company/operate_records',params)
+  },
+  // 机构列表数据
+  companyPageList:params=>{
+    return get('/company/page_list',params)
+  },
 };

+ 0 - 12
src/api/report/common.js

@@ -1,12 +0,0 @@
-import { get, post } from "@/api/index";
-
-export default {
-  //报告分类
-  classifyList: () => {
-    return get('/classify/list',{})
-  },
-  // 研报作者
-  reportAuthorList:()=>{
-    return get('/report_pdf/author',{})
-  }
-};

+ 0 - 9
src/api/report/index.js

@@ -1,9 +0,0 @@
-import apiReportCommon from './common'
-import apiReportPdf from './pdf'
-import apiReportPush from './reportPush'
-
-export {
-  apiReportCommon,
-  apiReportPdf,
-  apiReportPush
-}

+ 0 - 28
src/api/report/pdf.js

@@ -1,28 +0,0 @@
-import { get, post } from "@/api/index";
-
-export default {
-  //新增pdf报告
-  reportPdfAdd: params => {
-    return post('/report_pdf/add',params)
-  },
-  //编辑pdf报告
-  reportPdfEdit: params => {
-    return post('/report_pdf/edit',params)
-  },
-  //pdf报告列表
-  reportPdfList: params => {
-    return get('/report_pdf/list',params)
-  },
-  //pdf报告发布
-  reportPdfPubllish: params => {
-    return get('/report_pdf/publish',params)
-  },
-  //pdf报告取消发布
-  reportPdfCancelPubllish: params => {
-    return get('/report_pdf/publishCancel',params)
-  },
-  //pdf报告删除
-  reportPdfDelete: params => {
-    return get('/report_pdf/delete',params)
-  },
-};

+ 0 - 24
src/api/report/reportPush.js

@@ -1,24 +0,0 @@
-import { get, post } from "@/api/index";
-
-export default {
-  //推送报告列表
-  reportPushList: params => {
-    return get('/report_push/list',params)
-  },
-  //推送报告
-  reportPush: params => {
-    return post('report_push/push',params)
-  },
-  //撤销推送
-  reportPushCancel: params => {
-    return post('report_push/pushCancel',params)
-  },
-  //批量推送
-  reportBatchPush: params => {
-    return post('report_push/batch/push',params)
-  },
-  //批量撤销推送
-  reportBatchPushCancel: params => {
-    return post('report_push/batch/pushCancel',params)
-  },
-};

BIN
src/assets/imgs/avatar.png


BIN
src/assets/imgs/login_bg.png


BIN
src/assets/imgs/login_logo.png


BIN
src/assets/imgs/logo.png


+ 5 - 5
src/components/SelectReportClassify.vue

@@ -1,5 +1,5 @@
 <script setup>
-import { apiReportCommon } from '@/api/report'
+// import { apiReportCommon } from '@/api/report'
 
 const model=defineModel()
 const props=defineProps({
@@ -13,10 +13,10 @@ const emits=defineEmits(['change'])
 
 const options=ref([])
 async function getData(){
-  const res=await apiReportCommon.classifyList()
-  if(res.Ret!=200) return
-  const arr=res.Data||[]
-  options.value=arr
+  // const res=await apiReportCommon.classifyList()
+  // if(res.Ret!=200) return
+  // const arr=res.Data||[]
+  // options.value=arr
 }
 getData()
 

+ 42 - 38
src/layout/components/HeaderWrap.vue

@@ -1,14 +1,15 @@
 <script setup>
+import { computed, ref } from 'vue'
 import { useLayoutState } from '../hooks/index'
 import { useRoute, useRouter } from 'vue-router'
-import NoticeWrap from './NoticeWrap.vue'
-import {apiSystemMessage} from '@/api/system'
 
 const { menuClose, menuCloseChange } = useLayoutState()
 
 const router=useRouter()
 const route=useRoute()
-
+const userName=computed(()=>{
+  return localStorage.getItem('userName')
+})
 
 const breadcrumbArr=computed(()=>{
   const arr=route.matched
@@ -30,28 +31,32 @@ function handleClickBreadcrumb(e){
   // router.push()
 }
 
-
-// 阅读消息
-function handleReadNotice(){
-  apiSystemMessage.msgRead().then(res=>{
-    if(res.Ret===200){
-      hasUnRead.value=false
-    }
-  })
+function handleCommand (command) {
+  console.log(command);
+  if(command === 'resetpwd') {
+    router.push('/system/resetPwd')
+  } else {
+    ElMessageBox.confirm(
+      '确认退出吗?',
+      '提示',
+      { type: 'warning', }
+    ).then(() => {
+      localStorage.removeItem('token')
+      localStorage.removeItem('userName')
+      router.replace('/login')
+    }).catch()
+  }
 }
-const hasUnRead=ref(false)//是否有未读
-
-
 </script>
 
 <template>
   <div class="flex header-wrap">
-    <img src="@/assets/imgs/logo.png" alt="" class="logo-img">
+    <!-- <img src="@/assets/imgs/logo.png" alt="" class="logo-img"> -->
     <!-- 折叠按钮 -->
-    <el-icon size="26px" v-if="menuClose" @click="menuCloseChange"
+    <el-icon size="26px" v-if="menuClose" @click="menuCloseChange" color="#333333" style="margin-left: 100px;"
       ><i-ep-Expand
     /></el-icon>
-    <el-icon size="26px" v-else @click="menuCloseChange"><i-ep-Fold /></el-icon>
+    <el-icon size="26px" v-else @click="menuCloseChange" color="#333333" style="margin-left: 200px;"><i-ep-Fold /></el-icon>
     <!-- 面包屑 -->
     <el-breadcrumb separator="/" style="margin-left: 30px">
       <el-breadcrumb-item v-for="item,index in breadcrumbArr" :key="index" @click="handleClickBreadcrumb(item)">{{
@@ -60,14 +65,19 @@ const hasUnRead=ref(false)//是否有未读
     </el-breadcrumb>
     <div class="content"></div>
     <!-- 通知 -->
-    <el-popover placement="bottom" :width="500" trigger="click" @show="handleReadNotice" v-if="hasPermission('message:info')">
-      <template #reference>
-        <div :class="['system-notice-box',hasUnRead?'system-notice-box_red':'']">
-          <svg-icon name="notification-filled" size="18px"></svg-icon>
-        </div>
+    <el-dropdown placement="bottom" trigger="click" :width="100" @command="handleCommand">
+      <div :class="['system-notice-box']">
+        <!-- 哈喽 {{ userName }}, 欢迎您! -->
+        <img src="@/assets/imgs/avatar.png" alt="">
+        <div>{{ userName }}</div>
+      </div>
+      <template #dropdown>
+        <el-dropdown-menu>
+          <el-dropdown-item command="resetpwd">修改密码</el-dropdown-item>
+          <el-dropdown-item command="logout">退出登录</el-dropdown-item>
+        </el-dropdown-menu>
       </template>
-      <NoticeWrap @change="e=>hasUnRead=e"/>
-    </el-popover>
+    </el-dropdown>
   </div>
 </template>
 
@@ -79,11 +89,10 @@ const hasUnRead=ref(false)//是否有未读
   right: 0;
   height: 60px;
   z-index: 50;
-  background-color: #091F6B;
+  background-color: #fff;
   box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1);
   padding: 0 30px 0 0;
   align-items: center;
-  color: #fff;
   .logo-img{
     width: 140px;
     display: block;
@@ -92,7 +101,7 @@ const hasUnRead=ref(false)//是否有未读
   }
   :deep(.el-breadcrumb__item){
     .el-breadcrumb__inner{
-      color: #fff;
+      color: #053CC9;
     }
   }
 
@@ -100,17 +109,12 @@ const hasUnRead=ref(false)//是否有未读
     flex: 1;
   }
   .system-notice-box{
-    position: relative;
-    &.system-notice-box_red::after{
-      content: '';
-      display: block;
-      width: 6px;
-      height: 6px;
-      background-color: #f00;
-      border-radius: 6px;
-      position: absolute;
-      top: -2px;
-      right: -2px;
+    display: flex;
+    align-items: center;
+    img {
+      width: 28px;
+      height: 28px;
+      margin-right: 10px;
     }
   }
 }

+ 16 - 44
src/layout/components/LeftWrap.vue

@@ -22,28 +22,9 @@ const userName=computed(()=>{
   return localStorage.getItem('userName')
 })
 
-function resetpwd() {
-  router.push('/system/resetPwd')
-}
-
-function logout() {
-  ElMessageBox.confirm(
-    '确认退出吗?',
-    '提示',
-    { type: 'warning', }
-  ).then(() => {
-    localStorage.removeItem('token')
-    localStorage.removeItem('userName')
-    router.replace('/login')
-  }).catch()
-}
 
 function getMenuIcon(item){
-  if(item.Name==='用户列表') return 'menu/user'
-  if(item.Name==='潜在用户列表') return 'menu/usergroup'
-  if(item.Name==='PDF报告') return 'menu/pdf'
-  if(item.Name==='全局检索') return 'menu/usersearch'
-  if(item.Name==='推送报告APP') return 'menu/pushapp'
+  if(item.Name==='客户管理') return 'menu/user'
   return 'menu/setting'
 }
 
@@ -51,6 +32,9 @@ function getMenuIcon(item){
 
 <template>
   <div :class="['left-wrap', menuClose ? 'left-wrap__close' : '']">
+    <div class="logo-wrap">
+      <img src="@/assets/imgs/logo.png"  v-if="!menuClose" alt="" class="logo-img" />
+    </div>
     <el-menu
       class="menu-wrap"
       mode="vertical"
@@ -77,7 +61,7 @@ function getMenuIcon(item){
           </template>
           <el-menu-item
             v-for="child in level1.Children"
-            :index="child.Path"
+            :index="level1.Path + child.Path"
             :key="child.Path"
           >
             <!-- <el-icon></el-icon> -->
@@ -86,48 +70,36 @@ function getMenuIcon(item){
         </el-sub-menu>
       </template>
     </el-menu>
-    <div class="user-box" v-if="!menuClose">
-      <div class="name-box">
-        <svg-icon name="person" size="18px"></svg-icon>
-        <span>{{userName}}</span>
-      </div>
-      <div class="opt" @click="resetpwd">修改密码</div>
-      <div class="opt" @click="logout">退出登录</div>
-    </div>
-    <el-popover placement="right" :width="100" trigger="click">
-      <template #reference>
-        <div style="text-align: center">
-          <svg-icon name="person" size="24px" v-if="menuClose"></svg-icon>
-        </div>
-      </template>
-      <div>
-        <div style="text-align:center;padding:10px 0;cursor: pointer;" @click="resetpwd">修改密码</div>
-        <div style="text-align:center;padding:10px 0;cursor: pointer;" @click="logout">退出登录</div>
-      </div>
-    </el-popover>
   </div>
 </template>
 
 <style lang="scss" scoped>
 .left-wrap {
-  --el-menu-bg-color: #091f6b;
+  --el-menu-bg-color: #323A58;
   --el-menu-hover-bg-color: rgba(255, 255, 255, 0.15);
   --el-menu-text-color: #ffffff;
   --el-menu-active-color: #ffae4f;
   --el-menu-item-height: 40px;
   --el-menu-sub-item-height: 40px;
   width: 180px;
-  z-index: 50;
+  z-index: 90;
   position: fixed;
-  top: 60px;
+  top: 0px;
   left: 0;
   bottom: 0;
   padding: 8px;
-  background-color: #091f6b;
+  background-color: #323A58;
   display: flex;
   flex-direction: column;
   padding-bottom: 111px;
   transition: all 0.5s;
+  .logo-wrap {
+    img {
+      width: 100%;
+    }
+
+
+  }
   .menu-wrap {
     flex: 1;
     height: 100%;

+ 0 - 74
src/layout/components/NoticeWrap.vue

@@ -1,74 +0,0 @@
-<script setup>
-import { apiSystemMessage } from '@/api/system'
-import { useRouter , useRoute } from 'vue-router'
-
-const router=useRouter()
-const route=useRoute()
-
-const emits=defineEmits(['change'])
-
-const list = ref([])
-function getMsgList() {
-  apiSystemMessage.list().then(res => {
-    if (res.Ret === 200) {
-      list.value = res.Data.List || []
-      const hasUnRead=list.value.some(item=>!item.IsRead)
-      emits('change',hasUnRead)
-    }
-  })
-}
-getMsgList()
-
-function handleGoCustomerDetail(e){
-  if(route.path==='/customer/userDetail'){
-    router.replace('/customer/userDetail?id=' + e.UserId)
-    setTimeout(() => {
-      router.go(0)
-    }, 50);
-  }else{
-    router.push('/customer/userDetail?id=' + e.UserId)
-  }
-}
-
-
-</script>
-
-<template>
-  <div class="notice-wrap">
-    <div class="title">客户到期提醒</div>
-    <div class="list-wrap">
-      <div
-        :class="['item', item.IsRead ? 'item-read' : '']"
-        v-for="item in list"
-        :key="item.SysMessageReportId"
-        @click="handleGoCustomerDetail(item)"
-      >
-        <span style="margin-right: 20px">{{ item.Content }}</span>
-        <span>{{ item.CreateTime }}</span>
-      </div>
-    </div>
-  </div>
-</template>
-
-<style lang="scss" scoped>
-.notice-wrap {
-  .title {
-    padding: 20px 0;
-    border-bottom: 1px solid #e7e7e7;
-  }
-  .list-wrap {
-    max-height: 500px;
-    overflow-y: auto;
-    .item {
-      padding: 10px;
-      cursor: pointer;
-      span {
-        display: inline-block;
-      }
-    }
-    .item-read {
-      color: #999;
-    }
-  }
-}
-</style>

+ 4 - 1
src/main.js

@@ -11,6 +11,7 @@ import 'virtual:svg-icons-register'
 import registerGlobalComponents from '@/components/globalComponents';
 import {formatTime} from '@/utils/common'
 import {usePermission} from '@/hooks/permission'
+import * as permissionBtn from "@/utils/buttonConfig";
 
 const {hasPermission}=usePermission()
 
@@ -20,7 +21,9 @@ const app= createApp(App)
 app.config.globalProperties.formatTime=formatTime
 
 // 挂载一个全局的判断权限的方法
-app.config.globalProperties.hasPermission=hasPermission
+app.config.globalProperties.hasPermission = hasPermission
+// 挂载一个全局的按钮权限配置方法
+app.config.globalProperties.permissionBtn = permissionBtn
 
 // 注册全局指令
 import * as directives from '@/directives'

+ 59 - 29
src/router/modules/customer.js

@@ -6,15 +6,31 @@ export default[
     component:LayoutIndex,
     name:'CustomerIndex',
     meta:{
-      title:'用户列表'
+      title:'客户管理'
     },
-    children:[
+    children:[ 
       {
-        path:'userList',
+        path:'search_list',
+        component:()=>import('@/views/customer/UserSearch.vue'),
+        name:"CustomerUserSearch",
+        meta:{
+          title:'客户检索'
+        },
+      },
+      {
+        path:'customer_list',
         component:()=>import('@/views/customer/UserList.vue'),
         name:"CustomerUserList",
         meta:{
-          title:'基础信息'
+          title:'客户列表'
+        },
+      },
+      {
+        path:'trial_list',
+        component:()=>import('@/views/customer/PotentialUserList.vue'),
+        name:"CustomerPotentialUserList",
+        meta:{
+          title:'试用用户列表'
         },
       },
       {
@@ -22,9 +38,9 @@ export default[
         component:()=>import('@/views/customer/UserEdit.vue'),
         name:"CustomerUserAdd",
         meta:{
-          title:'新增用户',
-          from:'基础信息',
-          fromPath:'/customer/userList'
+          title:'新增投资者',
+          from:'客户列表',
+          fromPath:'/customer/customer_list'
         },
       },
       {
@@ -32,9 +48,9 @@ export default[
         component:()=>import('@/views/customer/UserEdit.vue'),
         name:"CustomerUserEdit",
         meta:{
-          title:'编辑用户',
-          from:'基础信息',
-          fromPath:'/customer/userList'
+          title:'编辑投资者',
+          from:'客户列表',
+          fromPath:'/customer/customer_list'
         },
       },
       {
@@ -42,25 +58,47 @@ export default[
         component:()=>import('@/views/customer/UserEdit.vue'),
         name:"CustomerUserDetail",
         meta:{
-          title:'用户详情',
-          from:'基础信息',
-          fromPath:'/customer/userList'
+          title:'投资者详情',
+          from:'客户列表',
+          fromPath:'/customer/customer_list'
         },
       },
       {
-        path:'userReportStatistic',
-        component:()=>import('@/views/customer/reportStatistic/Index.vue'),
-        name:"CustomerUserReportStatistic",
+        path:'companyAdd',
+        component:()=>import('@/views/customer/CompanyEdit.vue'),
+        name:"CustomerUserAdd",
         meta:{
-          title:'阅读统计'
+          title:'新增机构投资者',
+          from:'客户列表',
+          fromPath:'/customer/customer_list'
         },
       },
       {
-        path:'potentialUserList',
-        component:()=>import('@/views/customer/PotentialUserList.vue'),
-        name:"CustomerPotentialUserList",
+        path:'companyEdit',
+        component:()=>import('@/views/customer/CompanyEdit.vue'),
+        name:"CustomerUserEdit",
         meta:{
-          title:'潜在用户列表'
+          title:'编辑机构投资者',
+          from:'客户列表',
+          fromPath:'/customer/customer_list'
+        },
+      },
+      {
+        path:'companyDetail',
+        component:()=>import('@/views/customer/CompanyEdit.vue'),
+        name:"CustomerUserDetail",
+        meta:{
+          title:'机构投资者详情',
+          from:'客户列表',
+          fromPath:'/customer/customer_list'
+        },
+      },
+      {
+        path:'userReportStatistic',
+        component:()=>import('@/views/customer/reportStatistic/Index.vue'),
+        name:"CustomerUserReportStatistic",
+        meta:{
+          title:'阅读统计'
         },
       },
       {
@@ -73,14 +111,6 @@ export default[
           fromPath:'/customer/potentialUserList'
         },
       },
-      {
-        path:'userSearch',
-        component:()=>import('@/views/customer/UserSearch.vue'),
-        name:"CustomerUserSearch",
-        meta:{
-          title:'全局检索'
-        },
-      },
     ]
   }
 ]

+ 0 - 22
src/router/modules/pushapp.js

@@ -1,22 +0,0 @@
-import LayoutIndex from '@/layout/Index.vue'
-
-export default[
-  {
-    path:'/reportPushApp',
-    component:LayoutIndex,
-    name:'pushAppIndex',
-    meta:{
-      title:'报告推送app'
-    },
-    children:[
-      {
-        path:'reportList',
-        component:()=>import('@/views/pushReportList/index.vue'),
-        name:"PushReportList",
-        meta:{
-          title:'报告推送app'
-        },
-      },
-    ]
-  }
-]

+ 0 - 22
src/router/modules/report.js

@@ -1,22 +0,0 @@
-import LayoutIndex from '@/layout/Index.vue'
-
-export default[
-  {
-    path:'/report',
-    component:LayoutIndex,
-    name:'ReportIndex',
-    meta:{
-      title:'PDF报告'
-    },
-    children:[
-      {
-        path:'pdfList',
-        component:()=>import('@/views/report/pdf/List.vue'),
-        name:"ReportPdfList",
-        meta:{
-          title:'PDF报告'
-        },
-      },
-    ]
-  }
-]

+ 5 - 3
src/router/modules/system.js

@@ -10,7 +10,7 @@ export default[
     },
     children:[
       {
-        path:'userList',
+        path:'user_list',
         component:()=>import('@/views/system/userList/Index.vue'),
         name:"SystemUserList",
         meta:{
@@ -18,7 +18,7 @@ export default[
         },
       },
       {
-        path:'roleList',
+        path:'role_list',
         component:()=>import('@/views/system/RoleList.vue'),
         name:"SystemRoleList",
         meta:{
@@ -30,7 +30,9 @@ export default[
         component:()=>import('@/views/system/AuthSet.vue'),
         name:"SystemAuthSet",
         meta:{
-          title:'权限管理'
+          title:'权限管理',
+          from:'角色管理',
+          fromPath:'/system/role_list'
         },
       },
       {

+ 39 - 0
src/utils/buttonConfig.js

@@ -0,0 +1,39 @@
+/* 客户管理 */
+export const customerManageBtn={    
+    /* 客户检索 */
+    search_list:'search:list', // 查看列表
+
+    /* 客户列表 */
+    customer_list:'customer:list', // 查看列表
+    customer_add:'customer:add', // 新增客户
+    customer_edit:'customer:edit', // 编辑客户
+    customer_permissionSettings:'customer:permissionSettings', // 开启/关闭权限
+    customer_delete:'customer:delete', // 删除客户
+    customer_add:'contact:add', // 添加/编辑联系人
+    customer_delete:'contact:delete', // 删除联系人
+    customer_move:'contact:move', // 移动联系人
+
+    /* 试用列表 */
+    trial_list:'trial:list', // 查看列表
+    trial_convert:'trial:convert', // 转正式
+    trial_delete:'trial:delete', // 删除
+}
+
+/* 系统管理 */
+export const systemManageBtn={   
+    /* 用户管理 */
+    user_list:'user:list', // 查看列表
+    user_add:'user:add', // 添加/编辑用户
+    user_edit:'user:move', // 移动分组
+    user_permissionSettings:'user:permissionSettings', // 禁用/启用
+    user_delete:'user:delete', // 重置密码
+    user_addDept:'user:addDept', // 添加/编辑部门
+    user_deleteDept:'user:deleteDept', // 删除部门
+    user_moveDept:'user:moveDept', // 移动部门
+    
+    /* 角色管理 */
+    role_list:'role:list', // 查看列表
+    role_convert:'role:add', // 编辑添加角色
+    role_delete:'role:delete', // 删除角色
+    role_setting:'role:setting', // 权限设置
+}

+ 19 - 9
src/views/Login.vue

@@ -59,7 +59,7 @@ function getMenuList() {
       }
       let path = ''
       if (arr[0]?.Children[0]) {
-        path = arr[0].Children[0].Path
+        path = arr[0].Path + arr[0].Children[0].Path
       } else {
         path = arr[0].Path
       }
@@ -97,6 +97,9 @@ onMounted(() => {
     <div class="left-img-wrap">
       <img src="@/assets/imgs/login_bg.png" alt="">
     </div>
+    <div class="top-right">
+      <img src="@/assets/imgs/login_logo.png" alt="">
+    </div>
 
     <div class="form-wrap">
       <div class="form-content">
@@ -130,9 +133,9 @@ onMounted(() => {
           </el-form-item>
           <el-form-item>
             <el-button
-              style="width: 100%; margin-top: 50px"
+              style="width: 100%; margin-top: 50px; color: #ffffff;"
               type="primary"
-              color="#091F6B"
+              color="#409EFF"
               @click="submitForm(ruleFormRef)"
               >登录</el-button
             >
@@ -151,13 +154,20 @@ onMounted(() => {
   .left-img-wrap {
     width: 838px;
     height: 100%;
-    position: relative;
-    background-color: #091F6B;
+    display: flex;
+    justify-content: center;
+    align-items: center;
     img{
-      position: absolute;
-      bottom: 0;
-      right: 0;
-      width: 100%;
+      width: 90%;
+      height: 90%;
+    }
+  }
+  .top-right {
+    position: absolute;
+    top: 5%;
+    right: 5%;
+    img{
+      width: 230px;
     }
   }
   .form-wrap {

+ 262 - 0
src/views/customer/CompanyEdit.vue

@@ -0,0 +1,262 @@
+<script setup>
+import { apiCustomerUser } from '@/api/customer'
+import { useRoute, useRouter } from 'vue-router'
+import ContactTable from './components/ContactTable.vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import OperationRecord from './components/OperationRecord.vue'
+
+const route = useRoute()
+const router = useRouter()
+
+const CompanyId = ref(route.query.id || 0)
+
+const isView = computed(() => {
+  return route.path === '/customer/companyDetail'
+})
+
+
+const formRef = ref(null)
+const formRules = {
+  CompanyName: [{ required: true, message: '机构投资者名称不能为空', trigger: 'blur' }],
+  CreditCode: [{ required: true, message: '社会信用码不能为空', trigger: 'blur' }],
+  Industry: [{ required: true, message: '所属行业不能为空', trigger: 'blur' }],
+  SellerName: [{ required: true, message: '营业部不能为空', trigger: 'blur' }],
+}
+const formState = reactive({
+  CompanyName: '',
+  CreditCode: '',
+  Industry:'',
+  SellerName:'',
+  province: '',
+  city: '',
+})
+
+
+const checkedIds = ref([])
+
+function getUserInfo() {
+  if (!CompanyId.value) return
+  apiCustomerUser.companyInfo({
+    CompanyId: CompanyId.value
+  }).then(res => {
+    if (res.Ret === 200) {
+      const Detail = res.Data
+      formState.CompanyName = Detail.CompanyName
+      formState.CreditCode = Detail.CreditCode
+      formState.Industry = Detail.Industry
+      formState.SellerName = Detail.SellerName
+    }
+  })
+}
+getUserInfo()
+getSellerDepartment()
+
+const departmentList = ref([])
+async function getSellerDepartment() {
+  const res = await apiCustomerUser.sellerDepartmentList()
+  if (res.Ret === 200) {
+    departmentList.value = res.Data.List || []
+  }
+}
+
+
+function handleToEdit() {
+  // 关闭提示
+  formState.isEnabled=true
+  ElMessageBox.close()
+  router.replace({
+    path: '/customer/userEdit',
+    query: {
+      id: CompanyId.value
+    }
+  })
+}
+function checkAddContent(msg) {
+  return h('p', [
+    msg,
+    h(ElButton, {
+      type: 'primary',
+      link: true,
+      onClick: handleToEdit
+    }, '跳转查看')
+  ]);
+}
+
+
+
+async function handleSave(type) {
+  await formRef.value.validate()
+  const {CompanyName, CreditCode, Industry, SellerName} = formState
+
+  let params = {
+    CompanyName,
+    CreditCode,
+    Industry,
+    SellerName,
+  }
+  if (CompanyId.value) {
+    params.UserId = Number(CompanyId.value)
+    params.IsEnabled = formState.isEnabled
+  }
+  let res
+  if(route.name==='CustomerUserTransform'){
+    res=await apiCustomerUser.potentialUserEdit(params)
+  }else{
+    res = CompanyId.value ? await apiCustomerUser.companyEdit(params) : await apiCustomerUser.companyAdd(params)
+  }
+  if (res.Ret !== 200) return
+  ElMessage.success(CompanyId.value ? '编辑成功' : '新增成功')
+  router.replace('/customer/userList')
+}
+
+
+function selectRegion(data) {
+  formState.province = data.province.value;
+  formState.city = data.city.value == '市' ? '' : data.city.value;
+}
+</script>
+
+<template>
+  <div class="bg-white customer-user-edit-page">
+    <div class="top-box">
+      <div class="content-box">
+        <el-form
+          ref="formRef"
+          :model="formState"
+          :rules="formRules"
+          label-width="100px"
+          :disabled="isView"
+        >
+        <div class="auth-box-label">
+            <div class="text-icon"></div>
+            <h3 class="text">基础信息</h3>
+          </div>
+          <div class="flex form-tr-box">
+            <el-form-item label="投资者名称" prop="CompanyName">
+              <el-input v-model="formState.CompanyName" placeholder="请输入机构投资者名称全程" />
+            </el-form-item>
+            <el-form-item label="社会信用码" prop="CreditCode">
+              <el-input
+                v-model="formState.CreditCode"
+                placeholder="请输入社会信用码"
+              />
+            </el-form-item>
+          </div>
+          <div class="flex form-tr-box">
+            <el-form-item label="所属行业" prop="Industry">
+              <el-input v-model="formState.Industry" placeholder="请输入所属行业" />
+            </el-form-item>
+            <el-form-item label="客户地址" prop="province">
+              <div style="width: 100%">
+                <province-city-select
+                  :provinceInfo="formState.province"
+                  :cityInfo="formState.city"
+                  @selected="selectRegion"
+                />
+              </div>
+              <!-- <el-select
+                placeholder="请选择省份"
+                v-model="formState.SellerName"
+                clearable
+              >
+                <el-option v-for="(item, index) in province_sorce" :key="index" :label="item.SysDepartmentName" :value="item.SysDepartmentId"></el-option>
+              </el-select> -->
+            </el-form-item>
+          </div>
+          <div class="flex form-tr-box">
+            <el-form-item label="营业部" prop="CompanyId">
+              <el-select
+                placeholder="请选择营业部"
+                v-model="formState.Province"
+                clearable
+              >
+                <el-option v-for="(item, index) in departmentList" :key="index" :label="item.SysDepartmentName" :value="item.SysDepartmentId"></el-option>
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="flex form-tr-box" v-if="route.path !== '/customer/companyDetail'">
+            <el-form-item label="权限" prop="CompanyId">
+              可查看所有报告
+            </el-form-item>
+          </div>
+          <div class="flex form-tr-box color" v-if="route.path !== '/customer/companyDetail'">
+            *温馨提示:请确保投资者名称、社会信用码的正确性
+          </div>
+        </el-form>
+      </div>
+      <div class="right-box">
+        <div style="text-align: right" v-if="!isView">
+          <el-button type="primary" color="#0052D9" style="width: 120px" @click="handleSave"
+            >保存</el-button
+          >
+          <el-button
+            type="primary"
+            plain
+            @click="router.replace('/customer/userList')"
+            style="width: 120px"
+            >取消</el-button
+          >
+        </div>
+        <!-- 操作记录 -->
+        <OperationRecord v-else/>
+      </div>
+    </div>
+    <div class="form-tr-box auth-box" v-if="route.path === '/customer/companyDetail'">
+      <div class="auth-box-label">
+        <div class="text-icon"></div>
+        <h3 class="text">联系人信息</h3>
+      </div>
+      <el-button type="primary" color="#0052D9" style="width: 120px; margin-top: 10px;" @click="handleSave"
+          >添加联系人</el-button
+        >
+      <ContactTable
+        v-model:checkedIds="checkedIds"
+      />
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.customer-user-edit-page {
+  padding: 20px;
+}
+.top-box {
+  display: flex;
+  justify-content: space-between;
+  .content-box {
+    --el-switch-off-color: #333 !important;
+    --el-switch-on-color: #333 !important;
+    flex: 1;
+    margin-right: 30px;
+    .form-tr-box {
+      gap: 0 50px;
+      margin-bottom: 20px;
+      .el-form-item {
+        width: 45%;
+        max-width: 400px;
+      }
+    }
+    .color {
+      color: #D54941;
+    }
+  }
+  .right-box {
+    width: 350px;
+  }
+}
+.auth-box-label {
+  max-width: 850px;
+  display: flex;
+  align-items: center;
+  font-weight: bold;
+  .text-icon {
+    width: 2px;
+    height: 20px;
+    content: "";
+    background-color: #409EFF;
+    margin-right: 5px;
+  }
+  .text {
+  }
+}
+</style>

+ 20 - 138
src/views/customer/PotentialUserList.vue

@@ -17,70 +17,53 @@ const filterState = reactive({
 
 
 const tableColOpt = [
-  {
-    label: '手机号',
-    key: 'Phone'
-  },
   {
     label: '姓名',
     key: 'RealName'
   },
   {
-    label: '营业部',
-    key: 'SellerDepartmentName'
-  },
-  {
-    label: '邮箱',
-    key: 'Email'
+    label: '手机号',
+    key: 'Phone'
   },
   {
     label: '注册时间',
     key: 'RegisterTime',
     sort: true
   },
-  {
-    label: '申请时间',
-    key: 'ApplyTime',
-    sort: true
-  },
   {
     label: '最近一次阅读时间',
     key: 'LastUpdateTime',
     sort: true
   },
   {
-    label: '累计阅读次数',
+    label: '阅读统计',
     key: 'ReadCnt',
     sort: true,
   },
-  {
-    label: '申请状态',
-    key: 'ApplyStatus'
-  },
 ]
 const userList = ref([])
 const departmentList = ref([])
-const btnload = ref(false)
 const page = ref(1)
 const pageSize = ref(10)
 const tableLoading = ref(false)
 const totals = ref(0)
 async function getUserList() {
   tableLoading.value = true
-  const res = await apiCustomerUser.potentialUserList({
+  const res = await apiCustomerUser.userList({
     PageSize: pageSize.value,
     CurrentIndex: page.value,
-    KeyWord: filterState.keyword,
-    RegisterStartDate: filterState.regsiterTime ? filterState.regsiterTime[0] : '',
-    RegisterEndDate: filterState.regsiterTime ? filterState.regsiterTime[1] : '',
-    LastUpdateStartDate: filterState.readTime ? filterState.readTime[0] : '',
-    LastUpdateEndDate: filterState.readTime ? filterState.readTime[1] : '',
-    ApplyStartDate: filterState.appliTime ? filterState.appliTime[0] : '',
-    ApplyEndDate: filterState.appliTime ? filterState.appliTime[1] : '',
+    Keywords: filterState.keyword,
     ApplyStatus: filterState.ApplyStatus,
     SellerDepartmentId: filterState.SellerDepartmentId,
     SortParam: filterState.sortType,
-    SortType: filterState.sortVal
+    SortType: filterState.sortVal,
+    UserStatus: 1,
+    // CompanyId,
+    // StartTime, 
+    // EndTime,
+    // UserStatus,
+    // SortField: '',
+    // SortRule: '',
   })
   tableLoading.value = false
   if (res.Ret === 200) {
@@ -101,39 +84,6 @@ async function getSellerDepartment() {
 getSellerDepartment()
 getUserList()
 
-async function exportClick() {
-  btnload.value = true
-  const res = await apiCustomerUser.potentialExportExcel(
-    {
-    KeyWord: filterState.keyword,
-    RegisterStartDate: filterState.regsiterTime ? filterState.regsiterTime[0] : '',
-    RegisterEndDate: filterState.regsiterTime ? filterState.regsiterTime[1] : '',
-    LastUpdateStartDate: filterState.readTime ? filterState.readTime[0] : '',
-    LastUpdateEndDate: filterState.readTime ? filterState.readTime[1] : '',
-    ApplyStartDate: filterState.appliTime ? filterState.appliTime[0] : '',
-    ApplyEndDate: filterState.appliTime ? filterState.appliTime[1] : '',
-    ApplyStatus: filterState.ApplyStatus,
-    SellerDepartmentId: filterState.SellerDepartmentId,
-    }
-  )
-  btnload.value = false
-  console.log(res);
-  
-  const blob = new Blob([res], {
-    type: "application/vnd.ms-excel;charset=utf-8",
-  });
-  let fileName = '潜在用户列表' + dayjs(new Date()).format('YYYY-MM-DD') + ".xlsx";
-
-  const elink = document.createElement("a");
-  elink.download = fileName; //命名下载名称
-  elink.style.display = "none";
-  elink.href = URL.createObjectURL(blob);
-  document.body.appendChild(elink);
-  elink.click(); // 点击下载
-  URL.revokeObjectURL(elink.href); // 释放URL 对象
-  document.body.removeChild(elink); // 释放标
-  
-}
 
 function handlePageChange(e) {
   page.value = e
@@ -182,76 +132,12 @@ function handleShowDetail(e){
 <template>
   <div class="potential-user-list-page">
     <div class="flex filter-wrap">
-      <div>
-        <el-button type="primary" @click="exportClick" :loading="btnload"
-          >导出</el-button
-        >
-      </div>
-      <div class="flex filter-wrap">
-        <el-select
-          placeholder="请选择营业部"
-          v-model="filterState.SellerDepartmentId"
-          style="width: 165px"
-          clearable
-          @change="handleFilterList"
-        >
-          <el-option v-for="(item, index) in departmentList" :key="index" :label="item.SysDepartmentName" :value="item.SysDepartmentId"></el-option>
-        </el-select>
-      </div>
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.regsiterTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="注册时间"
-          end-placeholder="注册时间"
-          value-format="YYYY-MM-DD"
-          @change="handleFilterList"
-        />
-      </div>
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.appliTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="申请时间"
-          end-placeholder="申请时间"
-          value-format="YYYY-MM-DD"
-          @change="handleFilterList"
-        />
-      </div>
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.readTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="最近一次阅读时间"
-          end-placeholder="最近一次阅读时间"
-          value-format="YYYY-MM-DD"
-          @change="handleFilterList"
-        />
-      </div>
-      <div class="flex filter-wrap">
-        <el-select
-          placeholder="请选择申请状态"
-          v-model="filterState.ApplyStatus"
-          style="width: 165px"
-          clearable
-          @change="handleFilterList"
-        >
-          <el-option label="已申请" :value="1"></el-option>
-          <el-option label="未申请" :value="0"></el-option>
-        </el-select>
-      </div>
       <el-input
-        placeholder="手机号/邮箱"
+        placeholder="请输入机构名称/姓名/手机号"
         v-model="filterState.keyword"
         :prefix-icon="Search"
         clearable
-        style="max-width: 359px;margin-left:auto"
+        style="max-width: 359px;"
         @input="handleFilterList"
       />
     </div>
@@ -286,22 +172,18 @@ function handleShowDetail(e){
             </el-tooltip>
           </template>
           <template #default="{ row }">
-            <span
-              v-if="column.key === 'ApplyStatus'"
-              :style="{ color: row.ApplyStatus ? 'rgba(0, 136, 88, 1)' : '#f00' }"
-            >
-              {{ row.ApplyStatus ? "已申请" : "未申请" }}
-            </span>
-            <el-button v-else-if="column.key === 'ReadCnt'&&row.ReadCnt>0" link type="primary" @click="handleShowDetail(row)">{{row.ReadCnt}}</el-button>
+            <el-button v-if="column.key === 'ReadCnt'&&row.ReadCnt>0" link type="primary" @click="handleShowDetail(row)">{{row.ReadCnt}}</el-button>
             <span v-else>{{ row[column.key] }}</span>
           </template>
         </el-table-column>
         <el-table-column label="操作" align="center" width="200">
           <template #default="{ row }">
             <el-button type="primary" v-permission="'user:transform'" link @click="handleEditUser(row)"
-              >转客户</el-button
+              >转正式</el-button
+            >
+            <el-button type="primary" v-permission="'user:transform'" link @click="handleEditUser(row)"
+              >删除</el-button
             >
-            
           </template>
         </el-table-column>
       </el-table>

+ 0 - 6
src/views/customer/UserEdit.vue

@@ -3,7 +3,6 @@ import { apiSystemCommon } from '@/api/system'
 import { apiCustomerUser } from '@/api/customer'
 import { isMobileNo, patternEmail } from '@/utils/common'
 import { useRoute, useRouter } from 'vue-router'
-import PermissionTable from './components/PermissionTable.vue'
 import { dayjs, ElMessageBox } from 'element-plus'
 import OperationRecord from './components/OperationRecord.vue'
 
@@ -281,11 +280,6 @@ async function handleSave(type) {
               />
             </span>
           </div>
-
-          <PermissionTable
-            :userId="$route.query.id"
-            v-model:checkedIds="checkedIds"
-          />
         </div>
       </el-form>
     </div>

+ 210 - 195
src/views/customer/UserList.vue

@@ -4,100 +4,123 @@ import { apiCustomerUser } from '@/api/customer'
 import { useRouter } from 'vue-router'
 import { ElMessage, ElMessageBox,dayjs } from 'element-plus'
 import EnableUser from './components/EnableUser.vue'
+import { computed } from 'vue'
 
 const router = useRouter()
 
 const filterState = reactive({
   keyword: '',
   SellerDepartmentId: '',
-  status: '',
-  register: '',
-  subscribe: '',
-  regsiterTime: [],
   createTime: [],
   sortType:'',
   sortVal:''
 })
 
+const tableColOpt = computed( ()=>{
+  if (radio.value === 1) {
+    return [
+      {
+        label: '机构名称',
+        key: 'CompanyName'
+      },
+      {
+        label: '社会信用码',
+        key: 'CreditCode'
+      },
+      {
+        label: '所属行业',
+        key: 'Industry'
+      },
+      {
+        label: '客户地址',
+        key: 'Address'
+      },
+      {
+        label: '营业部',
+        key: 'SellerName',
+        width: '100px'
+      },
+      {
+        label: '创建时间',
+        key: 'CreateTime',
+        width: '200px'
+      },
+    ]
+  } else {
+    return [
+      {
+        label: '投资者姓名',
+        key: 'RealName'
+      },
+      {
+        label: '手机号',
+        key: 'MobileHidden'
+      },
+      {
+        label: '营业部',
+        key: 'SellerName'
+      },
+      {
+        label: '是否注册',
+        key: 'IsRegistered',
+        width: '100px'
+      },
+      {
+        label: '注册时间',
+        key: 'RegisterTime',
+        sort: true,
+        headerTips: '用户首次登录小程序的时间'
+      },
+      {
+        label: '是否关注公众号',
+        key: 'IsSubscribed' 
+      },
+      {
+        label: '创建时间',
+        key: 'CreateTime',
+        sort: true,
+        headerTips: '系统中新增该用户的时间'
+      },
+      { 
+        label: '最近一次阅读时间',
+        key: 'ModifyTime',
+        sort: true
+      },
+      {
+        label: '阅读统计',
+        key: 'ReadTimes',
+        sort: true
+      },
+    ]
+  }
+})
+
+const radio = ref(1)
 
-const tableColOpt = [
-  {
-    label: '姓名',
-    key: 'RealName'
-  },
-  {
-    label: '手机号',
-    key: 'Phone'
-  },
-  {
-    label: '邮箱',
-    key: 'Email'
-  },
-  {
-    label: '营业部',
-    key: 'SellerDepartmentName'
-  },
-  {
-    label: '用户状态',
-    key: 'Status',
-    width: '100px'
-  },
-  {
-    label: '有效期',
-    key: 'ValidStartTime',
-    width: '200px'
-  },
-  {
-    label: '到期时长',
-    key: 'RestDate',
-    sort: true,
-    width: '120px'
-  },
-  {
-    label: '是否注册',
-    key: 'IsRegistered',
-    width: '100px'
-  },
-  {
-    label: '注册时间',
-    key: 'RegisterTime',
-    sort: true,
-    headerTips: '用户首次登录小程序的时间'
-  },
-  {
-    label: '创建时间',
-    key: 'CreateTime',
-    sort: true,
-    headerTips: '系统中新增该用户的时间'
-  },
-  {
-    label: '是否关注公众号',
-    key: 'IsSubscribed'
-  },
-]
 const userList = ref([])
 const departmentList = ref([]) // 营业部列表
 const page = ref(1)
 const pageSize = ref(10)
 const tableLoading = ref(false)
 const totals = ref(0)
+
+
 async function getUserList() {
   tableLoading.value = true
-  const res = await apiCustomerUser.userList({
+  const parames = {
     PageSize: pageSize.value,
     CurrentIndex: page.value,
     SellerDepartmentId: filterState.SellerDepartmentId,
-    Status: filterState.status,
     KeyWord: filterState.keyword,
-    IsRegistered: filterState.register,
-    IsSubscribed: filterState.subscribe,
-    RegisterStartDate: filterState.regsiterTime ? filterState.regsiterTime[0] : '',
-    RegisterEndDate: filterState.regsiterTime ? filterState.regsiterTime[1] : '',
     CreateStartDate: filterState.createTime ? filterState.createTime[0] : '',
     CreateEndDate: filterState.createTime ? filterState.createTime[1] : '',
     SortParam:filterState.sortType,
-    SortType:filterState.sortVal
-  })
+    SortType:filterState.sortVal,
+    UserStatus: 2
+  }
+  console.log(radio.value === 1 ? 'companyPageList' : 'userList');
+  
+  const res = radio.value === 1 ? await apiCustomerUser.companyPageList(parames) : await apiCustomerUser.userList(parames)
   tableLoading.value = false
   if (res.Ret === 200) {
     userList.value = res.Data.List || []
@@ -110,17 +133,21 @@ function handlePageChange(e) {
   page.value = e
   getUserList()
 }
+
+function changeUser() {
+  getUserList()
+}
+
 async function getSellerDepartment() {
   tableLoading.value = true
   const res = await apiCustomerUser.sellerDepartmentList()
   tableLoading.value = false
   if (res.Ret === 200) {
-    departmentList.value = res.Data || []
+    departmentList.value = res.Data.List || []
   }
 }
 
 function handleTableSort(e) {
-  // console.log(e);
   const { order, prop } = e//order:"descending",prop: "RegisterTime"
   filterState.sortType=prop
   if(!order){
@@ -137,19 +164,6 @@ function handleFilterList() {
 }
 
 
-
-
-
-function handleEditUser(e) {
-  const link=router.resolve({
-    path: '/customer/userEdit',
-    query: {
-      id: e.UserId
-    }
-  }).href
-  window.open(link,'__blank')
-}
-
 // 禁用用户
 async function handleDisabledUser(row) {
   const res = await apiCustomerUser.setUserStatus({
@@ -187,123 +201,122 @@ function handleDelUser(row) {
   }).catch(() => { })
 }
 
+
+function handleEditUser(e) {
+  let link = ''
+  if (radio.value === 2) {
+    link = router.resolve({
+      path: '/customer/userEdit',
+      query: {
+        id: e.UserId
+      }
+    }).href
+  } else {
+    link = router.resolve({
+      path: '/customer/companyEdit',
+      query: {
+        id: e.CompanyId
+      }
+    }).href
+  }
+  window.open(link,'__blank')
+}
+
 // 跳转详情
 function handleGoDetail(e){
-  const link=router.resolve({
-    path:'/customer/userDetail',
-    query:{
-      id:e.UserId
-    }
-  }).href
+  let link = ''
+  if (radio.value === 2) {
+    link = router.resolve({
+      path:'/customer/userDetail',
+      query:{
+        id:e.UserId
+      }
+    }).href
+  } else {
+    link = router.resolve({
+      path:'/customer/companyDetail',
+      query:{
+        id:e.CompanyId
+      }
+    }).href
+  }
+
   window.open(link,'__blank')
 }
 
-
+function goAddUserPage() {
+  if (radio.value === 2) {
+    router.push('/customer/userAdd')
+  } else {
+    router.push('/customer/companyAdd')
+  }
+}
 </script>
 
 <template>
   <div class="customer-user-list-page">
-    <div>
-      <el-button
-        type="primary"
-        :icon="Plus"
-        @click="$router.push('/customer/userAdd')"
-        v-permission="'user:add'"
-        >新增</el-button
-      >
-      <el-input
-        placeholder="姓名/手机号/邮箱"
-        v-model="filterState.keyword"
-        :prefix-icon="Search"
-        clearable
-        style="max-width: 359px;float: right"
-        @input="handleFilterList"
-      />
+
+    <div class="select">
+      <el-radio-group v-model="radio" fill="#0052D9" size="large" @change="getUserList()">
+        <el-radio-button label="机构投资者" :value="1"></el-radio-button>
+        <el-radio-button label="个人投资者" :value="2"></el-radio-button>
+      </el-radio-group>
     </div>
-    <div class="flex filter-wrap">
-      <!-- <all-user-for-depart
-        style="width: 165px"
-        v-model="filterState.SellerDepartmentId"
-        :props="{
-          emitPath: false,
-          multiple: true,
-        }"
-        clearable
-        filterable
-        @change="handleFilterList"
-      /> -->
-      <el-select
-        placeholder="请选择营业部"
-        v-model="filterState.SellerDepartmentId"
-        style="width: 165px"
-        clearable
-        @change="handleFilterList"
-      >
-        <el-option v-for="(item, index) in departmentList" :key="index" :label="item.SysDepartmentName" :value="item.SysDepartmentId"></el-option>
-      </el-select>
-      <el-select
-        placeholder="用户状态"
-        v-model="filterState.status"
-        style="width: 165px"
-        @change="handleFilterList"
-        clearable
-      >
-        <el-option label="启用" value="正式"></el-option>
-        <el-option label="禁用" value="禁用"></el-option>
-      </el-select>
-      <el-select
-        placeholder="注册状态"
-        v-model="filterState.register"
-        style="width: 165px"
-        clearable
-        @change="handleFilterList"
-      >
-        <el-option label="是" value="是"></el-option>
-        <el-option label="否" value="否"></el-option>
-      </el-select>
-      <el-select
-        placeholder="是否关注公众号"
-        v-model="filterState.subscribe"
-        style="width: 165px"
-        clearable
-        @change="handleFilterList"
-      >
-        <el-option label="是" value="是"></el-option>
-        <el-option label="否" value="否"></el-option>
-      </el-select>
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.regsiterTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="注册时间"
-          end-placeholder="注册时间"
+
+    <div class="search-box">
+      <div class="flex filter-wrap">
+        <el-input
+          placeholder="请输入机构名称/联系人姓名/手机号"
+          v-model="filterState.keyword"
+          :prefix-icon="Search"
           clearable
-          value-format="YYYY-MM-DD"
-          @change="handleFilterList"
+          size="large"
+          style="max-width: 359px;float: right"
+          @input="handleFilterList"
         />
-      </div>
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.createTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="创建时间"
-          end-placeholder="创建时间"
-          value-format="YYYY-MM-DD"
+        <el-select
+          placeholder="请选择营业部"
+          v-model="filterState.SellerDepartmentId"
+          style="width: 165px"
           clearable
+          size="large"
           @change="handleFilterList"
-        />
+        >
+          <el-option v-for="(item, index) in departmentList" :key="index" :label="item.SysDepartmentName" :value="item.SysDepartmentId"></el-option>
+        </el-select>
+        <div style="width: 235px">
+          <el-date-picker
+            style="width: 235px"
+            v-model="filterState.createTime"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="创建时间"
+            end-placeholder="创建时间"
+            value-format="YYYY-MM-DD"
+            clearable
+            size="large"
+            @change="handleFilterList"
+          />
+        </div>
+        
+      </div>
+      <div>
+        <el-button
+          type="primary"
+          :icon="Plus"
+          size="large"
+          @click="goAddUserPage"
+          v-permission="'user:add'"
+          >新增</el-button
+        >
       </div>
-      
     </div>
-    <div class="userlist-wrap" style="margin-top: 20px">
+      
+    <div class="userlist-wrap" style="margin-top: 30px">
       <el-table
         :data="userList"
         border
-        stripe
+        
         highlight-current-row
         element-loading-text="数据加载中..."
         v-loading="tableLoading"
@@ -317,6 +330,7 @@ function handleGoDetail(e){
           :label="column.label"
           :sortable="column.sort ? 'custom' : false"
           :width="column.width"
+          align="center"
         >
           <template v-if="column.headerTips" #header>
             <span>{{ column.label }}</span>
@@ -332,12 +346,7 @@ function handleGoDetail(e){
             </el-tooltip>
           </template>
           <template #default="{ row }">
-            <span
-              v-if="column.key === 'Status'"
-              :style="{ color: !row.Status ? '#f00' : '' }"
-              >{{ row.Status ? "启用" : "禁用" }}</span
-            >
-            <span v-else-if="column.key === 'IsRegistered'">{{
+            <span v-if="column.key === 'IsRegistered'">{{
               row.IsRegistered ? "是" : "否"
             }}</span>
             <span v-else-if="column.key === 'IsSubscribed'">{{
@@ -357,33 +366,33 @@ function handleGoDetail(e){
             <span v-else>{{ row[column.key] }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" width="160">
+        <el-table-column label="操作" width="200" align="center">
           <template #default="{ row }">
             <el-button
-              v-permission="'user:edit'"
+              v-permission="permissionBtn.customerManageBtn.customer_edit"
               type="primary"
               link
               @click.stop="handleEditUser(row)"
               >编辑</el-button
             >
             <el-button
-              v-permission="'user:editEnabled'"
+              v-permission="permissionBtn.customerManageBtn.customer_permissionSettings"
               type="danger"
               link
-              v-if="row.Status"
+              v-if="row.Status === 2"
               @click.stop="handleDisabledUser(row)"
-              >禁用</el-button
+              >关闭权限</el-button
             >
             <el-button
-              v-permission="'user:editEnabled'"
+              v-permission="permissionBtn.customerManageBtn.customer_permissionSettings"
               type="primary"
               link
               v-else
               @click.stop="handleEnableUser(row)"
-              >启用</el-button
+              >开启权限</el-button
             >
             <el-button
-              v-permission="'user:delete'"
+              v-permission="permissionBtn.customerManageBtn.customer_delete"
               type="danger"
               link
               @click.stop="handleDelUser(row)"
@@ -416,8 +425,14 @@ function handleGoDetail(e){
 .customer-user-list-page {
   width: 100%;
   overflow: hidden;
+  .search-box {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
   .filter-wrap {
-    margin-top: 10px;
+    width: 70%;
+    margin-top: 20px;
     flex-wrap: wrap;
     gap: 10px;
   }

+ 58 - 211
src/views/customer/UserSearch.vue

@@ -1,185 +1,98 @@
 <script setup>
 import { Search } from '@element-plus/icons-vue'
 import { apiCustomerUser } from '@/api/customer'
-import UserStatisticDetail from './reportStatistic/components/UserStatisticDetail.vue'
-import EnableUser from './components/EnableUser.vue'
 import { useRouter } from 'vue-router'
 
-const router=useRouter()
+const router = useRouter()
 
-const filterState = reactive({
+const searchFilters = reactive({
   keyword: '',
   sortType: '',
   sortVal: ''
 })
 
-const tableColOpt = [
+const tableColumns = [
+  { label: '用户姓名', key: 'RealName' },
+  { label: '手机号', key: 'Mobile' },
+  { label: '注册时间', key: 'CreateTime' },
+  { label: '最近一次阅读时间', key: 'ModifyTime' },
   {
-    label: '姓名',
-    key: 'RealName'
-  },
-  {
-    label: '手机号',
-    key: 'Phone'
-  },
-  {
-    label: '邮箱',
-    key: 'Email'
-  },
-  {
-    label: '注册时间',
-    key: 'RegisterTime',
-    sort: true
-  },
-  {
-    label: '最近一次阅读时间',
-    key: 'LastUpdateTime',
-    sort: true
-  },
-  {
-    label: '累计阅读次数',
-    key: 'ReadCnt',
-    sort: true,
+    label: '阅读统计',
+    key: 'ReadTimes',
   },
 ]
+
 const userList = ref([])
 const page = ref(1)
 const pageSize = ref(10)
 const tableLoading = ref(false)
 const totals = ref(0)
-async function getUserList() {
-  if (!filterState.keyword) return
-  tableLoading.value = true
-  const res = await apiCustomerUser.userGlobalSearch({
-    PageSize: pageSize.value,
-    CurrentIndex: page.value,
-    KeyWord: filterState.keyword,
-    SortParam: filterState.sortType,
-    SortType: filterState.sortVal
-  })
-  tableLoading.value = false
-  if (res.Ret === 200) {
-    userList.value = res.Data.List || []
-    totals.value = res.Data.Paging.Totals
-  }
-}
-function handlePageChange(e) {
-  page.value = e
-  getUserList()
-}
-function handleTableSort(e) {
-  // console.log(e);
-  const { order, prop } = e//order:"descending",prop: "RegisterTime"
-  filterState.sortType = prop
-  if (!order) {
-    filterState.sortVal = ''
-  } else {
-    filterState.sortVal = order === 'descending' ? 'desc' : 'asc'
-  }
-
-  handleFilterList()
-}
-function handleFilterList() {
-  page.value = 1
-  totals.value = 0
-  userList.value = []
-  getUserList()
-}
 
-
-const showReadDetail = ref(false)
-const activeUserId = ref(0)
-const activeUserName = ref('')
-function handleShowReadDetail(e) {
-  activeUserId.value = e.UserId
-  activeUserName.value = e.RealName
-  showReadDetail.value = true
-}
-
-// 转客户
-function handleTransFormUser(e) {
-  router.push({
-    path: '/customer/userTransform',
-    query: {
-      id: e.UserId
+async function fetchUserList() {
+  if (!searchFilters.keyword) return
+  tableLoading.value = true
+  try {
+    const res = await apiCustomerUser.userGlobalSearch({
+      PageSize: pageSize.value,
+      CurrentIndex: page.value,
+      KeyWord: searchFilters.keyword,
+      SortParam: searchFilters.sortType,
+      SortType: searchFilters.sortVal
+    })
+    if (res.Ret === 200) {
+      updateUserList(res.Data.List || [])
+      updateTotals(res.Data.Paging.Totals)
+    } else {
+      console.error('Error fetching user list:', res)
+      // 可以考虑在这里添加用户友好的错误处理逻辑
     }
-  })
+  } catch (error) {
+    console.error('Error fetching user list:', error)
+    // 同样,这里也可以添加用户友好的错误处理逻辑
+  } finally {
+    tableLoading.value = false
+  }
 }
 
-function handleEditUser(e) {
-  const link=router.resolve({
-    path: '/customer/userEdit',
-    query: {
-      id: e.UserId
-    }
-  }).href
-  window.open(link,'__blank')
+function updateUserList(list) {
+  userList.value = list
 }
 
-// 禁用用户
-async function handleDisabledUser(row) {
-  const res = await apiCustomerUser.setUserStatus({
-    UserId: row.UserId,
-    IsEnabled: false
-  })
-  if (res.Ret !== 200) return
-  ElMessage.success('禁用成功')
-  userList.value=[]
-  getUserList()
+function updateTotals(total) {
+  totals.value = total
 }
 
-// 启用用户
-const showEnableUserPop = ref(false)
-const enableUserId = ref(0)
-function handleEnableUser(row) {
-  enableUserId.value = row.UserId
-  showEnableUserPop.value = true
+function handlePageChange(currentPage) {
+  page.value = currentPage
+  fetchUserList()
 }
 
-// 删除用户
-function handleDelUser(row) {
-  ElMessageBox.confirm(
-    '该操作会删除该用户所有相关信息,不可恢复,确认删除吗?',
-    '提示'
-  ).then(() => {
-    apiCustomerUser.userDelete({
-      UserId: row.UserId
-    }).then(res => {
-      if (res.Ret === 200) {
-        ElMessage.success('删除成功')
-        userList.value=[]
-        getUserList()
-      }
-
-    })
-  }).catch(() => { })
+function handleFilterList() {
+  page.value = 1
+  totals.value = 0
+  if (searchFilters.keyword) {
+    fetchUserList()
+  } else {
+    updateUserList([])
+  }
 }
 
-// 跳转详情
-function handleGoDetail(e){
-  if(e.Status===1) return
-  const link=router.resolve({
-    path:'/customer/userDetail',
-    query:{
-      id:e.UserId
-    }
-  }).href
-  window.open(link,'__blank')
+function handleGoDetail(row) {
+  if (row.Status === 1) return
+  router.push({ path: '/customer/userDetail', query: { id: row.UserId } })
 }
-
-
-
 </script>
 
 <template>
   <div class="user-search-page">
     <el-input
-      placeholder="姓名/手机号/邮箱"
-      v-model="filterState.keyword"
+      placeholder="请输入机构名称/姓名/手机号"
+      v-model="searchFilters.keyword"
       :prefix-icon="Search"
       clearable
+      v-permission="permissionBtn.customerManageBtn.search_list"
       style="max-width: 359px"
-      @change="handleFilterList"
+      @input="handleFilterList"
     />
     <div class="userlist-wrap" style="margin-top: 20px">
       <el-table
@@ -188,11 +101,10 @@ function handleGoDetail(e){
         highlight-current-row
         element-loading-text="数据加载中..."
         v-loading="tableLoading"
-        @sort-change="handleTableSort"
         @row-click="handleGoDetail"
       >
         <el-table-column
-          v-for="column in tableColOpt"
+          v-for="column in tableColumns"
           :key="column.key"
           :prop="column.key"
           :label="column.label"
@@ -207,64 +119,11 @@ function handleGoDetail(e){
               :content="column.headerTips"
               placement="top"
             >
-              <el-icon style="position: relative; top: 2px"
-                ><i-ep-QuestionFilled
-              /></el-icon>
+              <el-icon style="position: relative; top: 2px"><i-ep-QuestionFilled /></el-icon>
             </el-tooltip>
           </template>
           <template #default="{ row }">
-            <el-button
-              v-if="column.key === 'ReadCnt' && row.ReadCnt > 0"
-              link
-              type="primary"
-              @click.stop="handleShowReadDetail(row)"
-              >{{ row.ReadCnt }}</el-button
-            >
-            <span v-else>{{ row[column.key] || "--" }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="操作" align="center" width="200">
-          <template #default="{ row }">
-            <!-- 潜在 -->
-            <template v-if="row.Status === 1">
-              <el-button
-                type="primary"
-                v-if="hasPermission('user:globalTransform')"
-                link
-                @click="handleTransFormUser(row)"
-                >转客户</el-button
-              >
-            </template>
-            <template v-else>
-              <el-button
-                type="primary"
-                v-if="hasPermission('user:globalEdit')"
-                link
-                @click.stop="handleEditUser(row)"
-                >编辑</el-button
-              >
-              <el-button
-                type="danger"
-                link
-                v-if="hasPermission('user:globalEnabled')&&row.Status"
-                @click.stop="handleDisabledUser(row)"
-                >禁用</el-button
-              >
-              <el-button
-                type="primary"
-                link
-                v-if="hasPermission('user:globalEnabled')&&!row.Status"
-                @click.stop="handleEnableUser(row)"
-                >启用</el-button
-              >
-              <el-button
-                type="danger"
-                v-if="hasPermission('user:globalDelete')"
-                link
-                @click.stop="handleDelUser(row)"
-                >删除</el-button
-              >
-            </template>
+            <span>{{ row[column.key] || '--' }}</span>
           </template>
         </el-table-column>
       </el-table>
@@ -279,16 +138,4 @@ function handleGoDetail(e){
       />
     </div>
   </div>
-  <!-- 阅读统计 -->
-  <UserStatisticDetail
-    v-model:show="showReadDetail"
-    :userId="activeUserId"
-    :userName="activeUserName"
-  />
-  <!-- 开启用户 -->
-  <EnableUser
-    v-model:show="showEnableUserPop"
-    :userId="enableUserId"
-    @success="userList.value=[];getUserList()"
-  />
 </template>

+ 312 - 0
src/views/customer/components/ContactTable.vue

@@ -0,0 +1,312 @@
+<script setup>
+import { apiCustomerUser } from '@/api/customer'
+import { useRouter, useRoute } from 'vue-router'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { computed } from 'vue'
+
+const route = useRoute()
+const router = useRouter()
+
+const filterState = reactive({
+  sortType:'',
+  sortVal:''
+})
+
+const tableColOpt = computed( ()=>{
+  return [
+    {
+      label: '投资者姓名',
+      key: 'RealName'
+    },
+    {
+      label: '手机号',
+      key: 'MobileHidden'
+    },
+    {
+      label: '营业部',
+      key: 'SellerName'
+    },
+    {
+      label: '是否注册',
+      key: 'IsRegistered',
+      width: '100px'
+    },
+    {
+      label: '注册时间',
+      key: 'RegisterTime',
+      sort: true,
+      headerTips: '用户首次登录小程序的时间'
+    },
+    {
+      label: '是否关注公众号',
+      key: 'IsSubscribed' 
+    },
+    {
+      label: '创建时间',
+      key: 'CreateTime',
+      sort: true,
+      headerTips: '系统中新增该用户的时间'
+    },
+    { 
+      label: '最近一次阅读时间',
+      key: 'ModifyTime',
+      sort: true
+    },
+    {
+      label: '阅读统计',
+      key: 'ReadTimes',
+      sort: true
+    },
+  ]
+})
+
+const userList = ref([])
+const departmentList = ref([]) // 营业部列表
+const page = ref(1)
+const pageSize = ref(10)
+const tableLoading = ref(false)
+const totals = ref(0)
+
+
+async function getUserList() {
+  tableLoading.value = true
+  const parames = {
+    PageSize: pageSize.value,
+    CurrentIndex: page.value,
+    CompanyId: route.query.id,
+    SortParam:filterState.sortType,
+    SortType:filterState.sortVal,
+    UserStatus: 2
+  }
+  const res = await apiCustomerUser.userList(parames)
+  tableLoading.value = false
+  if (res.Ret === 200) {
+    userList.value = res.Data.List || []
+    totals.value = res.Data.Paging.Totals
+  }
+}
+getUserList()
+getSellerDepartment()
+function handlePageChange(e) {
+  page.value = e
+  getUserList()
+}
+
+async function getSellerDepartment() {
+  tableLoading.value = true
+  const res = await apiCustomerUser.sellerDepartmentList()
+  tableLoading.value = false
+  if (res.Ret === 200) {
+    departmentList.value = res.Data.List || []
+  }
+}
+
+function handleTableSort(e) {
+  const { order, prop } = e//order:"descending",prop: "RegisterTime"
+  filterState.sortType=prop
+  if(!order){
+    filterState.sortVal=''
+  }else{
+    filterState.sortVal=order==='descending'?'desc':'asc'
+  }
+  
+  handleFilterList()
+}
+function handleFilterList() {
+  page.value = 1
+  getUserList()
+}
+
+function handleEditUser(e) {
+  const link=router.resolve({
+    path: '/customer/userEdit',
+    query: {
+      id: e.UserId
+    }
+  }).href
+  window.open(link,'__blank')
+}
+
+// 禁用用户
+async function handleDisabledUser(row) {
+  const res = await apiCustomerUser.setUserStatus({
+    UserId: row.UserId,
+    IsEnabled: false
+  })
+  if (res.Ret !== 200) return
+  ElMessage.success('禁用成功')
+  getUserList()
+}
+
+// 启用用户
+const showEnableUserPop = ref(false)
+const enableUserId = ref(0)
+function handleEnableUser(row) {
+  enableUserId.value = row.UserId
+  showEnableUserPop.value = true
+}
+
+// 删除用户
+function handleDelUser(row) {
+  ElMessageBox.confirm(
+    '该操作会删除该用户所有相关信息,不可恢复,确认删除吗?',
+    '提示'
+  ).then(() => {
+    apiCustomerUser.userDelete({
+      UserId: row.UserId
+    }).then(res => {
+      if (res.Ret === 200) {
+        ElMessage.success('删除成功')
+        getUserList()
+      }
+
+    })
+  }).catch(() => { })
+}
+
+// 跳转详情
+function handleGoDetail(e){
+  let link = ''
+  if (radio.value === 2) {
+    link = router.resolve({
+      path:'/customer/userDetail',
+      query:{
+        id:e.UserId
+      }
+    }).href
+  } else {
+    link = router.resolve({
+      path:'/customer/companyDetail',
+      query:{
+        id:e.UserId
+      }
+    }).href
+  }
+
+  window.open(link,'__blank')
+}
+
+</script>
+
+<template>
+  <div class="customer-user-list-page">
+    <div class="userlist-wrap" style="margin-top: 30px">
+      <el-table
+        :data="userList"
+        border
+        
+        highlight-current-row
+        element-loading-text="数据加载中..."
+        v-loading="tableLoading"
+        @sort-change="handleTableSort"
+        @row-click="handleGoDetail"
+      >
+        <el-table-column
+          v-for="column in tableColOpt"
+          :key="column.key"
+          :prop="column.key"
+          :label="column.label"
+          :sortable="column.sort ? 'custom' : false"
+          :width="column.width"
+          align="center"
+        >
+          <template v-if="column.headerTips" #header>
+            <span>{{ column.label }}</span>
+            <el-tooltip
+              class="box-item"
+              effect="dark"
+              :content="column.headerTips"
+              placement="top"
+            >
+              <el-icon style="position: relative; top: 2px"
+                ><i-ep-QuestionFilled
+              /></el-icon>
+            </el-tooltip>
+          </template>
+          <template #default="{ row }">
+            <span v-if="column.key === 'IsRegistered'">{{
+              row.IsRegistered ? "是" : "否"
+            }}</span>
+            <span v-else-if="column.key === 'IsSubscribed'">{{
+              row.IsSubscribed ? "是" : "否"
+            }}</span>
+            <span v-else-if="column.key === 'ValidStartTime'"
+              >{{ formatTime(row.ValidStartTime, "YYYY-MM-DD") }}~{{
+                formatTime(row.ValidEndTime, "YYYY-MM-DD")
+              }}</span
+            >
+            <span v-else-if="column.key === 'RegisterTime'">{{
+              formatTime(row.RegisterTime)
+            }}</span>
+            <span v-else-if="column.key === 'CreateTime'">{{
+              formatTime(row.CreateTime)
+            }}</span>
+            <span v-else>{{ row[column.key] }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="200" align="center">
+          <template #default="{ row }">
+            <el-button
+              v-permission="permissionBtn.customerManageBtn.customer_edit"
+              type="primary"
+              link
+              @click.stop="handleEditUser(row)"
+              >编辑</el-button
+            >
+            <el-button
+              v-permission="permissionBtn.customerManageBtn.customer_permissionSettings"
+              type="danger"
+              link
+              v-if="row.Status === 2"
+              @click.stop="handleDisabledUser(row)"
+              >关闭权限</el-button
+            >
+            <el-button
+              v-permission="permissionBtn.customerManageBtn.customer_permissionSettings"
+              type="primary"
+              link
+              v-else
+              @click.stop="handleEnableUser(row)"
+              >开启权限</el-button
+            >
+            <el-button
+              v-permission="permissionBtn.customerManageBtn.customer_delete"
+              type="danger"
+              link
+              @click.stop="handleDelUser(row)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-pagination
+        background
+        layout="total,prev,pager,next,jumper"
+        :current-page="page"
+        :page-size="pageSize"
+        :total="totals"
+        @current-change="handlePageChange"
+        style="margin-top: 30px; justify-content: flex-end"
+      />
+    </div>
+  </div>
+
+</template>
+
+<style lang="scss" scoped>
+.customer-user-list-page {
+  width: 100%;
+  overflow: hidden;
+  .search-box {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  .filter-wrap {
+    width: 70%;
+    margin-top: 20px;
+    flex-wrap: wrap;
+    gap: 10px;
+  }
+}
+</style>

+ 7 - 9
src/views/customer/components/OperationRecord.vue

@@ -6,14 +6,12 @@ import { dayjs } from 'element-plus'
 const route = useRoute()
 
 const list = ref([])
-function getRecord() {
-  if(!route.query.id&&['/customer/userTransform','/customer/userAdd'].includes(route.path)) return
-  apiCustomerUser.userOperationRecord({
-    UserId: route.query.id
-  }).then(res => {
-    if (res.Ret !== 200) return
-    list.value = res.Data.List || []
-  })
+async function getRecord() {
+  if(!route.query.id) return
+  const routePath = route.path === '/customer/companyDetail'
+  const res = routePath ? await apiCustomerUser.companyOperationRecord({CompanyId: route.query.id}) : await apiCustomerUser.userOperationRecord({UserId: route.query.id})
+  if (res.Ret !== 200) return
+  list.value = res.Data || []
 }
 getRecord()
 
@@ -28,7 +26,7 @@ getRecord()
         :timestamp="dayjs(item.CreateTime).format('YYYY-MM-DD HH:mm:ss')"
         color="#4099ef"
       >
-        {{ item.Content }}
+        {{ item.Remark }}
       </el-timeline-item>
     </el-timeline>
   </div>

+ 0 - 207
src/views/customer/components/PermissionTable.vue

@@ -1,207 +0,0 @@
-<script setup>
-import { apiCustomerUser } from '@/api/customer'
-import { watch } from 'vue'
-
-const props = defineProps({
-  userId: {
-    type: [Number, String],
-    default: ''
-  }
-})
-
-const checkedIds = defineModel('checkedIds', { type: Array, default: [] })
-
-const opts = ref([])
-async function getAuthData() {
-  const res = await apiCustomerUser.userPermissionData({
-    UserId: props.userId || ''
-  })
-  if (res.Ret !== 200) return
-  opts.value = res.Data.List || []
-  const selectArr = res.Data.SelectedList || []
-  if (selectArr.length === 0) {
-    opts.value.forEach(item => {
-      item.PublicChild && item.PublicChild.forEach(_i => {
-        checkedIds.value.push(_i.ChartPermissionId)
-      })
-    });
-  } else {
-    checkedIds.value = res.Data.SelectedList
-  }
-
-}
-getAuthData()
-
-// 二级品种选中态改变
-function handleSelectChange(checked, item) {
-  console.log('二级品种选中态改变');
-  if (checked) {
-    checkedIds.value.push(item.ChartPermissionId)
-  } else {
-    checkedIds.value = checkedIds.value.filter(i => i !== item.ChartPermissionId)
-  }
-}
-
-// 一级品种选中态改变
-function handleChangeLevel1(checked, item) {
-  console.log('一级品种选中态改变');
-  if (checked) {
-    item.PrivateChild && item.PrivateChild.forEach(_i => {
-      if (!checkedIds.value.includes(_i.ChartPermissionId)) {
-        checkedIds.value.push(_i.ChartPermissionId)
-      }
-    })
-  } else {
-    //取消全选
-    let ids = []
-    item.PrivateChild && item.PrivateChild.forEach(_e => {
-      ids.push(_e.ChartPermissionId)
-    })
-    checkedIds.value = checkedIds.value.filter(_e => !ids.includes(_e))
-  }
-}
-
-// 控制一级品种的状态 0全没选中 1部分选中 2全选中
-function level1Status(item) {
-  let allCount = 0//一级品种总共有多少二级
-  let count = 0//当前有多少该一级品种下面的二级是选中的
-  if (item.PublicChild) {
-    allCount = allCount + item.PublicChild.length
-    count = count + item.PublicChild.length //公有的都选中
-  }
-  if (item.PrivateChild) {
-    allCount = allCount + item.PrivateChild.length
-    item.PrivateChild.forEach(_i => {
-      if (checkedIds.value.includes(_i.ChartPermissionId)) {
-        count++
-      }
-    })
-  }
-
-  if (count === 0) {//全没选中
-    return 0
-  } else if (count === allCount) {//全选中了
-    return 2
-  } else {//部分选中
-    return 1
-  }
-}
-
-//全选状态 0全没选中 1部分选中 2全选中
-const allSelectStatus = computed(() => {
-
-  let count = 0 //总共有多少二级品种
-  opts.value.forEach(item => {
-    if (item.PublicChild) {
-      count = count + item.PublicChild.length
-    }
-    if (item.PrivateChild) {
-      count = count + item.PrivateChild.length
-    }
-  })
-
-  if (checkedIds.value.length === 0) return 0
-  if (checkedIds.value.length > 0 && checkedIds.value.length < count) return 1
-  if (checkedIds.value.length === count) return 2
-})
-
-// 全选状态改变
-function handleChangeAll(checked) {
-  let arr=[]
-  opts.value.forEach(item => {
-    item.PublicChild?.forEach(_i=>{
-      arr.push(_i.ChartPermissionId)
-    })
-    if (checked){//权限将所有私有权限选中
-      item.PrivateChild?.forEach(_i=>{
-        arr.push(_i.ChartPermissionId)
-      })
-    }
-  })
-  checkedIds.value=arr
-}
-
-</script>
-
-<template>
-  <div class="permission-table-wrap">
-    <div class="item-wrap">
-      <div class="checkall-box">
-        <el-checkbox
-          :model-value="allSelectStatus === 2"
-          :indeterminate="allSelectStatus === 1"
-          @change="handleChangeAll"
-          >全选</el-checkbox
-        >
-      </div>
-    </div>
-    <div
-      class="item-wrap"
-      v-for="level1 in opts"
-      :key="level1.ChartPermissionId"
-    >
-      <div class="checkall-box">
-        <el-checkbox
-          @change="handleChangeLevel1($event, level1)"
-          :model-value="level1Status(level1) === 2"
-          :indeterminate="level1Status(level1) === 1"
-          >{{ level1.PermissionName }}</el-checkbox
-        >
-      </div>
-      <!-- 公有权限 -->
-      <div class="child-box" v-if="level1.PublicChild">
-        <span class="label-tag pub-tag">公有</span>
-        <el-checkbox
-          :model-value="checkedIds.includes(pubitem.ChartPermissionId)"
-          disabled
-          v-for="pubitem in level1.PublicChild"
-          :key="pubitem.ChartPermissionId"
-          >{{ pubitem.PermissionName }}</el-checkbox
-        >
-      </div>
-      <!-- 私有权限 -->
-      <div class="child-box" v-if="level1.PrivateChild">
-        <span class="label-tag pri-tag">私有</span>
-        <el-checkbox
-          :model-value="checkedIds.includes(priitem.ChartPermissionId)"
-          v-for="priitem in level1.PrivateChild"
-          :key="priitem.ChartPermissionId"
-          @change="handleSelectChange($event, priitem)"
-          >{{ priitem.PermissionName }}</el-checkbox
-        >
-      </div>
-    </div>
-  </div>
-</template>
-
-<style lang="scss" scoped>
-.permission-table-wrap {
-  margin-top: 10px;
-  margin-left: 60px;
-  border: 1px solid #ebeff6;
-  .item-wrap {
-    border-bottom: 1px solid #ebeff6;
-    .checkall-box {
-      border-bottom: 1px solid #ebeff6;
-      padding: 14px 16px;
-      background-color: #f9faff;
-    }
-    .child-box {
-      padding: 14px 16px;
-      .label-tag {
-        display: inline-block;
-        padding: 2px 3px;
-        margin-right: 10px;
-      }
-      .pub-tag {
-        color: #436cff;
-        background-color: #d1e4ff;
-      }
-      .pri-tag {
-        color: #edab29;
-        background-color: #fffaeb;
-      }
-    }
-  }
-}
-</style>

+ 0 - 219
src/views/pushReportList/components/bulkOperations.vue

@@ -1,219 +0,0 @@
-<script setup>
-    // import { Plus, CircleClose } from '@element-plus/icons-vue'
-    import { ElMessage } from 'element-plus'
-      import { apiReportPush } from '@/api/report'
-    // 接收父组件传递过来的数据
-    const emits = defineEmits(['success'])
-    const props = defineProps({
-        selectedRows:{
-            type: Array,
-            default: () => []
-        },
-        allHandUncheckDataId: {
-            type: Array,
-            default: () => []
-        },
-        filterState: {
-            type: Object,
-            default: () => {}
-        },
-        isSelectedAll: {
-            type: Boolean,
-            default: false
-        }
-    })
-    const show = defineModel('show', { type: Boolean, default: false })
-
-    const currentPage = ref(1);
-    const pageSize = ref(5);
-    const currentPageData = ref([])
-    const totalItems = ref(0);
-
-    // 获取数据
-    const getData = async () => {
-        console.log(props);
-        
-        let reqData = {
-            PageSize: pageSize.value,
-            CurrentIndex: currentPage.value,
-            ClassifyIds: props.filterState.classifyIds ? props.filterState.classifyIds.join(',') : '',
-            ChartPermissionIds: props.filterState.ChartPermissionIds.join(','),
-            PublishStartDate: props.filterState.publishTime?.[0] || '',
-            PublishEndDate: props.filterState.publishTime?.[1] || '',
-            PushStartDate: props.filterState.updateTime?.[0] || '',
-            PushEndDate: props.filterState.updateTime?.[1] || '',
-            KeyWord: props.filterState.keyword,
-            SortParam: props.filterState.sortType,
-            SortType: props.filterState.sortVal,
-        }
-        if (props.allHandUncheckDataId.length !== 0) {
-            reqData.SelectedIds = props.allHandUncheckDataId.join(',')
-            reqData.IsSelectAll = true
-        }
-        const res = await apiReportPush.reportPushList( reqData )
-        if (res.Ret === 200) {
-            currentPageData.value = res.Data.List || []
-            totalItems.value = res.Data.Paging.Totals
-        } else {
-        ElMessage.error('获取报告列表失败')
-      }
-    }
-
-    watch(show, (newValue) => {
-        if (newValue) {
-            console.log(props.isSelectedAll);
-            if (!props.isSelectedAll) {
-                totalItems.value = props.selectedRows.length;
-                const start = (currentPage.value - 1) * pageSize.value;
-                const end = start + pageSize.value;
-                // 计算当前页的数据 实现前端分页
-                currentPageData.value = props.selectedRows.slice(start, end);
-            } else {
-                getData() // 当show变为true时,获取数据
-            }
-        }
-    })
-
-    // 分页状态
-    // function getdata() {
-
-    // }
-
-    // 方法
-    // 处理分页当前页变化
-    function handleCurrentChange(val) {
-      currentPage.value = val;
-      if (!props.isSelectedAll) {
-        const start = (val - 1) * pageSize.value;
-        const end = val * pageSize.value;
-        // 计算当前页的数据 实现前端分页
-        currentPageData.value = props.selectedRows.slice(start, end);
-      } else {
-        getData()
-      }
-    }
-    // 取消
-    function Cancel() {
-        show.value=false
-    }
-
-    // 撤销
-    async function Revoke() {
-        // 调用接口
-        let reqData = {
-            ClassifyIds: props.filterState.classifyIds ? props.filterState.classifyIds : [],
-            ChartPermissionIds: props.filterState.ChartPermissionIds ? props.filterState.ChartPermissionIds : [],
-            PublishStartDate: props.filterState.publishTime?.[0] || '',
-            PublishEndDate: props.filterState.publishTime?.[1] || '',
-            PushStartDate: props.filterState.updateTime?.[0] || '',
-            PushEndDate: props.filterState.updateTime?.[1] || '',
-            KeyWord: props.filterState.keyword,
-        }
-        if (props.isSelectedAll) {
-            reqData.SelectedIds = props.allHandUncheckDataId
-            reqData.IsSelectAll = true
-        } else {
-            const selectedRowsId = props.selectedRows.map(item => item.ReportPushStatusId)
-            reqData.SelectedIds = selectedRowsId
-            reqData.IsSelectAll = false
-        }
-        const res = await apiReportPush.reportBatchPushCancel(reqData)
-        if (res.Ret === 200) {
-            ElMessage.success('撤销成功')
-            show.value=false
-            // 刷新数据
-            emits('success')
-        } else {
-            ElMessage.error(res.Msg)
-        }
-    }
-    // 推送APP
-    async function PushApp() {
-        // 调用接口
-        let reqData = {
-            ClassifyIds: props.filterState.classifyIds ? props.filterState.classifyIds : [],
-            ChartPermissionIds: props.filterState.ChartPermissionIds ? props.filterState.ChartPermissionIds : [],
-            PublishStartDate: props.filterState.publishTime?.[0] || '',
-            PublishEndDate: props.filterState.publishTime?.[1] || '',
-            PushStartDate: props.filterState.updateTime?.[0] || '',
-            PushEndDate: props.filterState.updateTime?.[1] || '',
-            KeyWord: props.filterState.keyword,
-        }
-        if (props.isSelectedAll) {
-            reqData.SelectedIds = props.allHandUncheckDataId
-            reqData.IsSelectAll = true
-        } else {
-            const selectedRowsId = props.selectedRows.map(item => item.ReportPushStatusId)
-            reqData.SelectedIds = selectedRowsId
-            reqData.IsSelectAll = false
-        }
-        const res = await apiReportPush.reportBatchPush(reqData)
-        if (res.Ret === 200) {
-            ElMessage.success('推送成功')
-            show.value=false
-            // 刷新数据
-            emits('success')
-        } else {
-            ElMessage.error(res.Msg)
-        }
-    }
-</script>
-
-<template>
-  <el-dialog v-model="show" width="600" title="批量操作" draggable>
-    <div class="box-dialog">
-        <div class="count">
-            已选择{{totalItems}}篇报告
-        </div>
-        <div class="table">
-            <el-table :data="currentPageData" border>
-                <el-table-column prop="Title" label="标题" align="center"></el-table-column>
-                <el-table-column prop="State" label="状态" width="130px" align="center">
-                    <template #default="{ row }">
-                        <!-- <el-tag :type="row.State === 1 ? 'info' : 'success'" effect="dark">{{ row.State === 1 ? '已推送' : '未推送' }}</el-tag> -->
-                        <text>{{ row.State === 1 ? '已推送' : '未推送' }}</text>
-                    </template>
-                </el-table-column>
-            </el-table>
-            <div class="pagination">
-                <el-pagination
-                    pager-count="3"
-                    background
-                    @current-change="handleCurrentChange"
-                    :current-page="currentPage"
-                    :page-size="pageSize"
-                    layout="prev, pager, next"
-                    :total="totalItems"
-                    style="margin-top: 30px; width: 55%; justify-content: space-between;"
-                />
-            </div>  
-        </div>
-        <div class="footer">
-            <el-button :plain="true" @click="Cancel" size="large" style="width: 120px;">取消</el-button>
-            <el-button type="primary" v-permission="'reportPush:batchPushCancel'" @click="Revoke" size="large" style="width: 120px;">撤销</el-button>
-            <el-button type="primary" v-permission="'reportPush:batchPush'" @click="PushApp" size="large" style="width: 120px;">推送APP</el-button>
-        </div>
-    </div>
-  </el-dialog>
-</template>
-
-<style lang="scss" scoped>
-.box-dialog {
-    width: 500px;
-    margin: 0 auto;
-    .count{
-        margin: 20px 0;
-    }
-    .table {
-        .pagination{
-            display: flex;
-            justify-content: flex-end;
-        }
-    }
-    .footer {
-        margin: 30px 0;
-        display: flex;
-        justify-content: space-between ;
-    }
-}
-</style>

+ 0 - 437
src/views/pushReportList/index.vue

@@ -1,437 +0,0 @@
-<script setup>
-  import { Search, Plus } from '@element-plus/icons-vue'
-  import BulkOperations from './components/bulkOperations.vue'
-  import { apiReportPush } from '@/api/report'
-  import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
-import { tr } from 'element-plus/es/locale/index.mjs';
-
-  const filterState = reactive({
-    keyword: '',
-    classifyIds: [], // 改为数组,减少转换逻辑
-    ChartPermissionIds: [],
-    publishTime: [],
-    updateTime: [],
-    sortType: '',
-    sortVal: ''
-  })
-
-  // 表格数据
-  const currentPageData = ref([])
-  const page = ref(1)
-  const pageSize = ref(10)
-  const tableLoading = ref(false)
-  const totals = ref(0)
-  const selectedRows = ref([]); // 存储选中的行
-  const selectAll = ref(false) // 全选状态
-  const isSelectAll = ref(false);
-  const tableRef = ref(null); // 表格引用
-  const showBulkOperations = ref(false); // 批量操作弹窗
-  const selectReportNum = ref(0); // 当前报告篇数(因为有全选所以不能用.length)
-  const uncheckData = ref([]) // 取消选中的数据
-  const isHandleSelect = ref(false) // 标记是否手动处理的选中
-  const allHandUncheckData = ref([]) // 全部取消选中数据
-  const allHandUncheckDataId = ref([])
-
-  // 表格列配置
-  const tableColOpt = ref([
-    { label: '报告标题', key: 'Title'},
-    { label: '类型', key: 'ClassifyNameFirst' },
-    { label: '作者', key: 'Author', width: '150px'},
-    { label: '摘要', key: 'Abstract' },
-    { label: '发布/审批时间', key: 'PublishTime', sort: true, width: '200px' },
-    { label: '推送时间', key: 'PushTime', sort: true, width: '200px' },
-    { label: '状态', key: 'State', width: '100px'},
-  ])
-
-  function getTitleTime(e) {
-    if (e.PublishTime) {
-      return dayjs(e.PublishTime).format('MMDD')
-    }
-    return dayjs(e.ModifyTime).format('MMDD')
-  }
-
-  // 获取列表数据
-  async function getReportList() {
-    tableLoading.value = true
-    try {
-      const res = await apiReportPush.reportPushList({
-        PageSize: pageSize.value,
-        CurrentIndex: page.value,
-        ClassifyIds: filterState.classifyIds ? filterState.classifyIds.join(',') : '',
-        ChartPermissionIds: filterState.ChartPermissionIds.join(','),
-        PublishStartDate: filterState.publishTime?.[0] || '',
-        PublishEndDate: filterState.publishTime?.[1] || '',
-        PushStartDate: filterState.updateTime?.[0] || '',
-        PushEndDate: filterState.updateTime?.[1] || '',
-        KeyWord: filterState.keyword,
-        SortParam: filterState.sortType,
-        SortType: filterState.sortVal,
-      })
-      if (res.Ret === 200) {
-        isHandleSelect.value = false // 标记手动处理选中
-        allHandUncheckData.value = [...allHandUncheckData._value, ...uncheckData._value] // 在数据更新前缓存全部取消选中数据
-        // 数组去重
-        allHandUncheckData.value = [...new Set(allHandUncheckData._value)]
-        currentPageData.value = res.Data.List || []
-        totals.value = res.Data.Paging.Totals
-        handleCurrentChange() // 在每次数据更新后,更新表格当前选中数据
-      } else {
-        ElMessage.error('获取报告列表失败')
-      }
-    } catch (error) {
-      ElMessage.error('发生错误: ' + error.message)
-    } finally {
-      tableLoading.value = false
-    }
-  }
-
-  // 获取列表数据
-  getReportList()
-
-  function handlePageChange(e) {
-    page.value = e
-    getReportList()
-  }
-  function handleTableSort(e) {
-    const { order, prop } = e // 直接使用,无需额外注释
-    filterState.sortType = prop
-    filterState.sortVal = order === 'descending' ? 'desc' : order === 'ascending' ? 'asc' : ''
-    handleFilterList()
-  }
-  function handleFilterList() {
-    page.value = 1
-    getReportList()
-  }
-
-  // 手动选择行的时候添加标记
-  function handleSelect(selection) {
-    isHandleSelect.value = true
-  }
-
-  // 处理多选变更
-  function handleSelectionChange(val) {
-    selectedRows.value = val
-    // console.log(isHandleSelect._value);
-    if (isSelectAll._value) {
-      allHandUncheckData.value = allHandUncheckData._value.filter( item => val.findIndex(element => element.ReportId === item.ReportId) === -1) // 从所有取消选中数据中过滤出当前页数据中重新选中的数据
-      // selectReportNum.value = totals._value // 更新当前报告篇数
-      selectReportNum.value = totals._value - allHandUncheckData._value.length // 更新当前报告篇数
-      if (isHandleSelect._value) {
-        uncheckData.value = currentPageData._value.filter( item => val.findIndex(element => element.ReportId === item.ReportId) === -1) // 获取当前页数据中,未选中的数据
-        selectReportNum.value = selectReportNum._value - uncheckData._value.length // 更新当前报告篇数
-        // 判断当前选中数据是否为全部数据,如果为全部数据,则更新全选按钮状态
-        if (selectReportNum.value < totals._value) {
-          selectAll.value = false
-        } else {
-          selectAll.value = true
-          isSelectAll.value = true // 更新全选按钮状态;
-        }
-      }
-    } else {
-      selectReportNum.value = val.length // 更新当前报告篇数
-    }
-  }
-
-  // 点击全选按钮
-  function clickCheckbox() {
-    isSelectAll.value = !isSelectAll.value;
-    handleCurrentChange('allCheck') // 点击全选按钮之后,更新表格当前选中数据
-  }
-
-  // 更改当前选中数据状态
-  function handleCurrentChange(val) {
-    if (isSelectAll.value) { // 如果全选按钮为选中状态,则把当前页数据全部选中
-      const rows = currentPageData.value // 注意:这里只是当前组件中的数据,对于后端分页来说,你可能需要不同的逻辑
-      rows.forEach(row => {
-        // console.log(11);
-        const index = selectedRows.value.findIndex(element => element.ReportId === row.ReportId) // 判断当前表格选中数据中是否包含该行数据
-        const indexed = allHandUncheckData.value.findIndex(element => element.ReportId === row.ReportId) // 判断当前表格数据是否包含手动未选中的数据
-        if (index === -1 && indexed === -1) { // 如果当前表格选中数据中不包含该行数据,则添加到表格选中数据中
-          tableRef.value.toggleRowSelection(row, isSelectAll.value); // 选中当前页数据
-        }
-      });
-    } else {
-      if (val === 'allCheck') {
-        tableRef.value.clearSelection() // 如果全选按钮为非选中状态,则清空表格选中数据
-        allHandUncheckData.value = [] // 清空手动未选中的数据
-      }
-    }
-  }
-
-  // 批量操作
-  function bulkOperations() {
-    console.log(selectAll);
-    // 反选的数据
-
-    allHandUncheckDataId.value = [...allHandUncheckData._value, ...uncheckData._value].map(item => item.ReportPushStatusId) // 获取当前表格选中数据中,手动未选中的数据
-    selectedRows.value.length > 0 ? showBulkOperations.value = true : ElMessage.warning('请选择报告');
-  }
-
-  // 撤销
-  async function handleReportCancelPublish(e){
-    await ElMessageBox.confirm('是否确认撤销改报告','提示')
-    const res=await apiReportPush.reportPushCancel({
-      ReportPushStatusId:e.ReportPushStatusId
-    })
-    if(res.Ret===200){
-      ElMessage.success('撤销成功')
-      handleFilterList()
-    }
-  }
-
-  // 推送
-  async function handleReportPublish(e){
-    const res=await apiReportPush.reportPush({
-      ReportPushStatusId:e.ReportPushStatusId
-    })
-    if(res.Ret===200){
-      ElMessage.success('推送APP成功')
-      handleFilterList()
-    }
-  }
-
-
-  function getClassifyName(e){
-    if (!e) {
-      return ''; // 如果传入的e为空或undefined,直接返回空字符串
-    }
-    if(e.ClassifyNameThird){
-      return `${e.ClassifyNameFirst}/${e.ClassifyNameSecond}/${e.ClassifyNameThird}`
-    }else if(e.ClassifyNameSecond){
-      return `${e.ClassifyNameFirst}/${e.ClassifyNameSecond}`
-    }else{
-      return e.ClassifyNameFirst
-    }
-    return ''
-  }
-
-  function success(res) {
-    // tableRef.value.clearSelection() // 如果批量推送完成清空表格选中数据
-    // selectedRows.value.forEach(row => {
-    //   tableRef.value.toggleRowSelection(row, isSelectAll.value); // 选中当前页数据
-    // });
-    handleFilterList()
-  }
-
-</script>
-
-<template>
-  <div class="report-pdf-list-page">
-    <!-- 查询标题 -->
-    <div class="top-right">
-      <el-input
-        placeholder="报告标题"
-        v-model="filterState.keyword"
-        :prefix-icon="Search"
-        clearable
-        style=""
-        @input="handleFilterList"
-      />
-      <div class="select">
-        <el-checkbox v-model="selectAll" @change="clickCheckbox" label="列表全选" size="large" />
-        <div class="select-title">已选择 {{ selectReportNum }} 篇报告</div>
-      </div>
-    </div>
-    <div class="flex filter-wrap">
-      <!-- 分类 -->
-      <select-report-classify
-        v-model="filterState.classifyIds"
-        clearable
-        :props="{
-          emitPath: false,
-          multiple: true,
-        }"
-        @change="handleFilterList"
-      />
-
-      <!-- 状态 -->
-      <!-- <el-select
-        placeholder="状态"
-        v-model="filterState.status"
-        style="width: 165px"
-        clearable
-        @change="handleFilterList"
-      >
-        <el-option label="已发布" :value="1"></el-option>
-        <el-option label="未发布" :value="2"></el-option>
-      </el-select> -->
-      <select-permission
-        v-model="filterState.ChartPermissionIds"
-        :props="{
-          emitPath: false,
-          multiple: true,
-        }"
-        clearable
-        @change="handleFilterList"
-      />
-
-      <!-- 发布时间 -->
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.publishTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="发布时间"
-          end-placeholder="发布时间"
-          clearable
-          value-format="YYYY-MM-DD"
-          @change="handleFilterList"
-        />
-      </div>
-      
-      <!-- 更新时间 -->
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.updateTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="推送时间"
-          end-placeholder="推送时间"
-          value-format="YYYY-MM-DD"
-          clearable
-          @change="handleFilterList"
-        />
-      </div>
-
-      <!-- 批量操作 -->
-        <el-button type="primary" @click="bulkOperations" :filterState="filterState">批量操作</el-button>
-
-    </div>
-    <div class="list-wrap">
-      <el-table
-        :data="currentPageData"
-        size="default"
-        border
-        highlight-current-row
-        element-loading-text="数据加载中..."
-        v-loading="tableLoading"
-        @sort-change="handleTableSort"
-        @selection-change="handleSelectionChange"
-        @select="handleSelect"
-        :row-key="(row) => row.ReportId"
-        ref="tableRef"
-      >
-        <!-- 多选列 -->
-        <el-table-column
-          type="selection"
-          width="55"
-          :reserve-selection="true"
-        ></el-table-column>
-        <!-- 数据列 -->
-        <el-table-column
-          v-for="column in tableColOpt"
-          :key="column.key"
-          :prop="column.key"
-          :label="column.label"
-          :sortable="column.sort ? 'custom' : false"
-          :width="column.width"
-        >
-          <template v-if="column.headerTips" #header>
-            <span>{{ column.label }}</span>
-            <el-tooltip
-              class="box-item"
-              effect="dark"
-              raw-content
-              :content="column.headerTips"
-              placement="top"
-            >
-              <el-icon style="position: relative; top: 2px"
-                ><i-ep-QuestionFilled
-              /></el-icon>
-            </el-tooltip>
-          </template>
-          <template #default="{ row }">
-            <span v-if="column.key === 'Title'"
-              >{{ row.Title }}({{ getTitleTime(row) }})</span
-            >
-            <span v-else-if="column.key === 'ClassifyNameFirst'">{{getClassifyName(row)}}</span>
-            <span v-else-if="column.key === 'State'">{{
-              row.State === 1 ? "已推送" : "未推送"
-            }}</span>
-            <span v-else-if="column.key === 'PublishTime'">{{
-              formatTime(row.PublishTime)
-            }}</span>
-            <span v-else-if="column.key === 'Abstract'">{{ row.Abstract === '' ? '/' : row.Abstract }} </span>
-
-            <span v-else-if="column.key === 'ModifyTime'">{{
-              formatTime(row.ModifyTime)
-            }}</span>
-            <span v-else>{{ row[column.key] }}</span>
-          </template>
-        </el-table-column>
-        <!-- 操作列 -->
-        <el-table-column label="操作" width="100">
-          <template #default="{ row }">
-            <el-button
-              v-permission="'reportPush:pushCancel'"
-              type="danger"
-              link
-              v-if="row.State === 1"
-              @click="handleReportCancelPublish(row)"
-              >撤销</el-button
-            >
-            <el-button
-              v-permission="'reportPush:push'"
-              type="primary"
-              link
-              v-if="row.State ===  0"
-              @click="handleReportPublish(row)"
-              >推送APP</el-button
-            >
-          </template>
-        </el-table-column>
-      </el-table>
-      <!-- 分页 -->
-      <el-pagination
-        background
-        layout="total,prev,pager,next,jumper"
-        :current-page="page"
-        :page-size="pageSize"
-        :total="totals"
-        @current-change="handlePageChange"
-        style="margin-top: 30px; justify-content: flex-end"
-      />
-    </div>
-  </div>
-  <!-- 批量操作弹窗 -->
-  <BulkOperations 
-    v-model:show="showBulkOperations" 
-    :selectedRows="selectedRows"
-    :allHandUncheckDataId="allHandUncheckDataId"
-    :filterState="filterState"
-    :isSelectedAll ="isSelectAll"
-    @success="success"
-  />
-</template>
-
-<style lang="scss" scoped>
-.list-wrap {
-  margin-top: 10px;
-}
-.report-pdf-list-page {
-  width: 100%;
-  overflow: hidden;
-  .filter-wrap {
-    // margin-top: 10px;
-    flex-wrap: wrap;
-    gap: 10px;
-  }
-  .top-right {
-    width: 400px;
-    float: right;
-    .select {
-      margin-top: 30px;
-      width: 400px;
-      display: flex;
-      justify-content: flex-end;
-      display: flex;
-      align-items: center;
-      .select-title {
-        margin-left: 20px;
-      }
-    }
-  }
-}
-</style>

+ 0 - 360
src/views/report/pdf/List.vue

@@ -1,360 +0,0 @@
-<script setup>
-import { Search, Plus } from '@element-plus/icons-vue'
-import EditPdf from './components/EditPdf.vue'
-import { apiReportPdf } from '@/api/report'
-import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
-
-const filterState = reactive({
-  keyword: '',
-  classifyIds: '',
-  status: '',
-  publishTime: [],
-  updateTime: [],
-  sortType:'',
-  sortVal:''
-})
-
-const tableColOpt = [
-  {
-    label: '报告标题',
-    key: 'Title'
-  },
-  {
-    label: '类型',
-    key: 'ClassifyNameFirst'
-  },
-  {
-    label: '作者',
-    key: 'Author'
-  },
-  {
-    label: '摘要',
-    key: 'Abstract'
-  },
-  {
-    label: '状态',
-    key: 'State',
-    width: '100px'
-  },
-  {
-    label: '创建人',
-    key: 'SysRealName'
-  },
-  {
-    label: '发布时间',
-    key: 'PublishTime',
-    sort: true,
-    width: '200px'
-  },
-  {
-    label: '更新时间',
-    key: 'ModifyTime',
-    sort: true,
-    width: '200px'
-  },
-  {
-    label: '期数',
-    key: 'Stage',
-    width: '100px'
-  },
-  {
-    label: 'PV/UV',
-    key: 'Pv',
-    headerTips: 'pv:报告被打开的次数,每次打开都计算一次<br> uv:访问报告的人数,每篇报告同一个人访问只计算一次'
-  }
-]
-function getTitleTime(e) {
-  if (e.PublishTime) {
-    return dayjs(e.PublishTime).format('MMDD')
-  }
-  return dayjs(e.ModifyTime).format('MMDD')
-}
-
-const pdfList = ref([])
-const page = ref(1)
-const pageSize = ref(10)
-const tableLoading = ref(false)
-const totals = ref(0)
-async function getReportList() {
-  tableLoading.value = true
-  const res = await apiReportPdf.reportPdfList({
-    PageSize: pageSize.value,
-    CurrentIndex: page.value,
-    ClassifyIds:filterState.classifyIds ? filterState.classifyIds.join(',') : '',
-    State:filterState.status,
-    PublishStartDate:filterState.publishTime ? filterState.publishTime[0] : '',
-    PublishEndDate:filterState.publishTime ? filterState.publishTime[1] : '',
-    ModifyStartDate:filterState.updateTime ? filterState.updateTime[0] : '',
-    ModifyEndDate:filterState.updateTime ? filterState.updateTime[1] : '',
-    KeyWord:filterState.keyword,
-    SortParam:filterState.sortType,
-    SortType:filterState.sortVal
-  })
-  tableLoading.value = false
-  if (res.Ret === 200) {
-    pdfList.value = res.Data.List || []
-    totals.value = res.Data.Paging.Totals
-  }
-}
-getReportList()
-function handlePageChange(e) {
-  page.value = e
-  getReportList()
-}
-function handleTableSort(e) {
-  // console.log(e);
-  const { order, prop } = e//order:"descending",prop: "RegisterTime"
-  filterState.sortType = prop
-  if (!order) {
-    filterState.sortVal = ''
-  } else {
-    filterState.sortVal = order === 'descending' ? 'desc' : 'asc'
-  }
-
-  handleFilterList()
-}
-function handleFilterList() {
-  page.value = 1
-  getReportList()
-}
-
-
-const showEdit = ref(false)
-const editData = ref(null)
-function handleEditPdf(e){
-  editData.value=e
-  showEdit.value=true
-}
-
-async function handleReportCancelPublish(e){
-  await ElMessageBox.confirm('是否确认撤销改报告','提示')
-  const res=await apiReportPdf.reportPdfCancelPubllish({
-    ReportPdfId:e.ReportPdfId
-  })
-  if(res.Ret===200){
-    ElMessage.success('撤销成功')
-    handleFilterList()
-  }
-}
-
-async function handleReportPublish(e){
-  const res=await apiReportPdf.reportPdfPubllish({
-    ReportPdfId:e.ReportPdfId
-  })
-  if(res.Ret===200){
-    ElMessage.success('发布成功')
-    handleFilterList()
-  }
-}
-
-async function handleReportDelete(e){
-  await ElMessageBox.confirm('报告删除后无法恢复,确认删除吗?','提示')
-  const res=await apiReportPdf.reportPdfDelete({
-    ReportPdfId:e.ReportPdfId
-  })
-  if(res.Ret===200){
-    ElMessage.success('删除成功')
-    handleFilterList()
-  }
-}
-
-function handlePreviewPdf(e){
-  window.open(e.PdfUrl,'__blank')
-}
-
-function getClassifyName(e){
-  if(e.ClassifyNameThird){
-    return `${e.ClassifyNameFirst}/${e.ClassifyNameSecond}/${e.ClassifyNameThird}`
-  }else if(e.ClassifyNameSecond){
-    return `${e.ClassifyNameFirst}/${e.ClassifyNameSecond}`
-  }else{
-    return e.ClassifyNameFirst
-  }
-}
-
-</script>
-
-<template>
-  <div class="report-pdf-list-page">
-    <div>
-      <el-button v-permission="'reportPdf:add'" type="primary" :icon="Plus" @click="showEdit = true;editData=null"
-        >上传报告</el-button
-      >
-      <el-input
-        placeholder="报告标题/创建人"
-        v-model="filterState.keyword"
-        :prefix-icon="Search"
-        clearable
-        style="max-width: 359px; float: right"
-        @input="handleFilterList"
-      />
-    </div>
-    <div class="flex filter-wrap">
-      <select-report-classify
-        v-model="filterState.classifyIds"
-        clearable
-        :props="{
-          emitPath: false,
-          multiple: true,
-        }"
-        @change="handleFilterList"
-      />
-      <el-select
-        placeholder="状态"
-        v-model="filterState.status"
-        style="width: 165px"
-        clearable
-        @change="handleFilterList"
-      >
-        <el-option label="已发布" :value="1"></el-option>
-        <el-option label="未发布" :value="2"></el-option>
-      </el-select>
-
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.publishTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="发布时间"
-          end-placeholder="发布时间"
-          clearable
-          value-format="YYYY-MM-DD"
-          @change="handleFilterList"
-        />
-      </div>
-      <div style="width: 235px">
-        <el-date-picker
-          style="width: 235px"
-          v-model="filterState.updateTime"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="更新时间"
-          end-placeholder="更新时间"
-          value-format="YYYY-MM-DD"
-          clearable
-          @change="handleFilterList"
-        />
-      </div>
-    </div>
-    <div class="list-wrap" style="margin-top: 20px">
-      <el-table
-        :data="pdfList"
-        border
-        stripe
-        highlight-current-row
-        element-loading-text="数据加载中..."
-        v-loading="tableLoading"
-        @sort-change="handleTableSort"
-      >
-        <el-table-column
-          v-for="column in tableColOpt"
-          :key="column.key"
-          :prop="column.key"
-          :label="column.label"
-          :sortable="column.sort ? 'custom' : false"
-          :width="column.width"
-        >
-          <template v-if="column.headerTips" #header>
-            <span>{{ column.label }}</span>
-            <el-tooltip
-              class="box-item"
-              effect="dark"
-              raw-content
-              :content="column.headerTips"
-              placement="top"
-            >
-              <el-icon style="position: relative; top: 2px"
-                ><i-ep-QuestionFilled
-              /></el-icon>
-            </el-tooltip>
-          </template>
-          <template #default="{ row }">
-            <span v-if="column.key === 'Title'"
-              @click="handlePreviewPdf(row)"
-              >{{ row.Title }}({{ getTitleTime(row) }})</span
-            >
-            <span v-else-if="column.key === 'ClassifyNameFirst'">{{getClassifyName(row)}}</span>
-            <span v-else-if="column.key === 'State'">{{
-              row.State === 1 ? "已发布" : "未发布"
-            }}</span>
-            <span v-else-if="column.key === 'PublishTime'">{{
-              formatTime(row.PublishTime)
-            }}</span>
-            <span v-else-if="column.key === 'ModifyTime'">{{
-              formatTime(row.ModifyTime)
-            }}</span>
-            <span v-else-if="column.key === 'Stage'">第{{ row.Stage }}期</span>
-            <span v-else-if="column.key === 'Pv'"
-              >{{ row.Pv }} / {{ row.Uv }}</span
-            >
-            <span v-else>{{ row[column.key] }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="操作" width="160">
-          <template #default="{ row }">
-            <el-button
-              v-permission="'reportPdf:edit'"
-              type="primary"
-              link
-              @click="handleEditPdf(row)"
-              >编辑</el-button
-            >
-            <el-button
-              v-permission="'reportPdf:publishCancel'"
-              type="primary"
-              link
-              v-if="row.State===1"
-              @click="handleReportCancelPublish(row)"
-              >撤销</el-button
-            >
-            <el-button
-              v-permission="'reportPdf:publish'"
-              type="primary"
-              link
-              v-if="row.State===2"
-              @click="handleReportPublish(row)"
-              >发布</el-button
-            >
-            <el-button
-              v-permission="'reportPdf:delete'"
-              type="danger"
-              link
-              v-if="row.State===2"
-              @click="handleReportDelete(row)"
-              >删除</el-button
-            >
-            
-          </template>
-        </el-table-column>
-      </el-table>
-      <el-pagination
-        background
-        layout="total,prev,pager,next,jumper"
-        :current-page="page"
-        :page-size="pageSize"
-        :total="totals"
-        @current-change="handlePageChange"
-        style="margin-top: 30px; justify-content: flex-end"
-      />
-    </div>
-  </div>
-
-  <EditPdf 
-    v-model:show="showEdit" 
-    :defaultData="editData"
-    @success="handleFilterList"
-  />
-</template>
-
-<style lang="scss" scoped>
-.report-pdf-list-page {
-  width: 100%;
-  overflow: hidden;
-  .filter-wrap {
-    margin-top: 10px;
-    flex-wrap: wrap;
-    gap: 10px;
-  }
-}
-</style>

+ 0 - 176
src/views/report/pdf/components/EditPdf.vue

@@ -1,176 +0,0 @@
-<script setup>
-import { Plus, CircleClose } from '@element-plus/icons-vue'
-import SelectAuthor from './SelectAuthor.vue'
-import {apiReportPdf} from '@/api/report'
-import { ElMessage } from 'element-plus'
-
-const show = defineModel('show', { type: Boolean, default: false })
-const emits=defineEmits(['success'])
-
-const props=defineProps({
-  defaultData:{
-    type:[Object,null],
-    default:null
-  }
-})
-
-const formIns = ref(null)
-const FORM_RULES = {
-  title: [{ required: true, message: '请填写报告标题' }],
-  classify:[{ required: true, message: '请选择报告分类' }]
-}
-const formData = reactive({
-  fileUrl: '',
-  fileName: '',
-  title: "",
-  classify: '',
-  abstract: '',
-  author: ''
-})
-
-watch(()=>show.value,(n)=>{
-  if(n&&props.defaultData){
-    formData.fileUrl=props.defaultData.PdfUrl
-    formData.fileName=props.defaultData.PdfName
-    formData.title=props.defaultData.Title
-    if(props.defaultData.ClassifyIdThird){
-      formData.classify=[props.defaultData.ClassifyIdFirst,props.defaultData.ClassifyIdSecond,props.defaultData.ClassifyIdThird]
-    }else if(props.defaultData.ClassifyIdSecond){
-      formData.classify=[props.defaultData.ClassifyIdFirst,props.defaultData.ClassifyIdSecond]
-    }else{
-      formData.classify=[props.defaultData.ClassifyIdFirst]
-    }
-    
-    formData.abstract=props.defaultData.Abstract
-    formData.author=props.defaultData.Author?props.defaultData.Author.split(','):''
-  }else{
-    for(let key in formData){
-      formData[key]=''
-    }
-  }
-})
-
-function handleUploadSuccess(e) {
-  formData.fileUrl = e.Url
-  formData.fileName = e.FileName
-  if(!formData.title){
-    formData.title=e.FileName
-  }
-  
-}
-
-async function onSubmit() {
-  await formIns.value.validate()
-  if(!formData.fileUrl) {
-    ElMessage.warning('请上传报告PDF文件')
-    return
-  }
-  const params={
-    PdfUrl:formData.fileUrl,
-    PdfName:formData.fileName,
-    Title:formData.title,
-    Author:formData.author?formData.author.join(','):'',
-    Abstract:formData.abstract,
-    ClassifyIdFirst:formData.classify?formData.classify[0]:0,
-    ClassifyIdSecond:formData.classify?formData.classify[1]||0:0,
-    ClassifyIdThird:formData.classify?formData.classify[2]||0:0,
-  }
-  const res=props.defaultData?await apiReportPdf.reportPdfEdit({
-    ReportPdfId:props.defaultData.ReportPdfId,
-    ...params,
-  }):await apiReportPdf.reportPdfAdd(params)
-
-  if(res.Ret===200){
-    ElMessage.success('保存成功')
-    show.value=false
-    emits('success')
-  }
-
-}
-
-</script>
-
-<template>
-  <el-dialog v-model="show" width="700" :title="props.defaultData?'编辑':'上传报告'" draggable>
-    <el-form
-      ref="formIns"
-      label-width="80px"
-      :rules="FORM_RULES"
-      :model="formData"
-      @submit="onSubmit"
-      class="form-wrap"
-    >
-      <upload-file
-        accept="application/pdf"
-        :fileSize="15"
-        @success="handleUploadSuccess"
-        class="upload-box"
-      >
-        <div v-if="formData.fileUrl" class="file-name-box">
-          <span style="font-size:18px;color:var(--el-primary-color)">{{ formData.fileName }}</span>
-          <el-icon color="#f00" size="20px" @click="formData.fileName='';formData.fileUrl=''"><CircleClose /></el-icon>
-        </div>
-        <template #trigger>
-          <el-button
-            class="upload-btn"
-            type="primary"
-            plain
-            :icon="Plus"
-            v-if="!formData.fileUrl"
-            >上传报告</el-button
-          >
-        </template>
-
-        <template #tip>
-          <div>要求文件格式为pdf,且不超过15M</div>
-        </template>
-      </upload-file>
-
-      <el-form-item label="报告标题" prop="title">
-        <el-input v-model="formData.title" placeholder="请输入报告标题" />
-      </el-form-item>
-      <el-form-item label="分类" prop="classify">
-        <select-report-classify style="width:100%" v-model="formData.classify"/>
-      </el-form-item>
-      <el-form-item label="摘要" prop="abstract">
-        <el-input
-          type="textarea"
-          v-model="formData.abstract"
-          placeholder="请输入报告摘要"
-        />
-      </el-form-item>
-      <el-form-item label="作者" prop="author">
-        <SelectAuthor multiple v-model="formData.author" />
-      </el-form-item>
-    </el-form>
-
-    <div style="text-align: center">
-      <el-button type="primary" plain size="large" @click="show = false"
-        >取消</el-button
-      >
-      <el-button type="primary" size="large" @click="onSubmit">保存</el-button>
-    </div>
-  </el-dialog>
-</template>
-
-<style lang="scss" scoped>
-.form-wrap {
-  width: 500px;
-  margin: 0 auto;
-}
-.upload-box {
-  text-align: center;
-  margin-bottom: 20px;
-  .file-name-box{
-    margin-bottom: 20px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: 0 10px;
-  }
-  .upload-btn {
-    width: 500px;
-    margin-bottom: 10px;
-  }
-}
-</style>

+ 0 - 47
src/views/report/pdf/components/SelectAuthor.vue

@@ -1,47 +0,0 @@
-<script setup>
-import { apiReportCommon } from '@/api/report'
-
-const model = defineModel()
-const props = defineProps({
-  props: {},
-  clearable: {
-    type: Boolean,
-    default: false
-  },
-  multiple: {
-    type: Boolean,
-    default: false
-  },
-
-})
-const emits = defineEmits(['change'])
-
-const options = ref([])
-async function getData() {
-  const res = await apiReportCommon.reportAuthorList()
-  if (res.Ret != 200) return
-  const arr = res.Data || []
-  options.value = arr
-}
-getData()
-
-function handleChange() {
-  emits('change')
-}
-
-</script>
-<template>
-  <el-select
-    collapse-tags
-    :multiple="props.multiple"
-    v-model="model"
-    placeholder="请选择作者"
-  >
-    <el-option
-      v-for="item in options"
-      :key="item.Id"
-      :label="item.ReportAuthor"
-      :value="item.ReportAuthor"
-    />
-  </el-select>
-</template>

+ 60 - 48
src/views/system/AuthSet.vue

@@ -1,24 +1,22 @@
 <script setup>
 import { apiSystemRole } from '@/api/system'
+import { useRoute } from 'vue-router'
+const route = useRoute()
 
-
-// 获取角色
-const roleId = ref('')
-const roleArr = ref([])
-async function getRoleList() {
-  const res = await apiSystemRole.roleAllList()
-  if (res.Ret !== 200) return
-  const list = res.Data.List || []
-  roleArr.value = list
-  roleId.value = list[0].SysRoleId
-  handlRoleChange()
-}
-getRoleList()
-const isAdmin=computed(()=>{
-  if(!roleArr.value.length) return false
-  return roleArr.value.filter(item=>item.SysRoleId===roleId.value)[0].SysRoleName==='admin'
+// 角色信息
+const roleId = ref(route.query.SysRoleId)
+const roleName = ref(route.query.SysRoleName||'')
+const isAdmin = computed( ()=> {
+  return route.query.SysRoleName === 'admin'
 })
 
+const checkboxTree=ref(null)
+const loading=ref(false)
+const defaultCheckedKeys = ref([])
+const authList = ref([])
+
+getRoleAuthData()
+
 function disabledTree(arr){
   arr.forEach(item => {
     item.Disabled=true
@@ -29,10 +27,6 @@ function disabledTree(arr){
   return arr
 }
 
-const checkboxTree=ref(null)
-const loading=ref(false)
-const defaultCheckedKeys = ref([])
-const authList = ref([])
 async function getRoleAuthData(){
   loading.value=true
   const res=await apiSystemRole.roleAuthList({
@@ -86,36 +80,31 @@ function handleSave(){
 
 <template>
   <div class="system-authset-page">
-    <div class="shadow-box top-box">
-      <div style="width: 300px; display: flex; align-items: center">
-        <span style="flex-shrink: 0; margin-right: 20px">角色</span>
-        <el-select v-model="roleId" placeholder="分配角色" @change="handlRoleChange">
-          <el-option
-            v-for="item in roleArr"
-            :key="item.SysRoleId"
-            :label="item.SysRoleName"
-            :value="item.SysRoleId"
-          >
-          </el-option>
-        </el-select>
+    <el-card>
+      <div class="shadow-box top-box">
+        <div style="width: 300px; display: flex; align-items: center">
+          <span style="flex-shrink: 0; margin-right: 20px">角色</span>
+          <h3>{{ roleName }}</h3>
+        </div>
+        <!-- <div v-if="!isAdmin"> -->
+          <div>
+          <el-button type="primary" plain @click="$router.back()">取消</el-button>
+          <el-button v-permission="permissionBtn.systemManageBtn.role_setting" type="primary" :disabled="loading" @click="handleSave">保存</el-button>
+        </div>
       </div>
-      <div v-if="!isAdmin">
-        <el-button v-permission="'permission:cancel'" type="primary" plain @click="$router.back()">取消</el-button>
-        <el-button v-permission="'permission:save'" type="primary" :disabled="loading" @click="handleSave">保存</el-button>
+      <div class="shadow-box content-box" v-loading="loading" element-loading-text="loading...">
+        <el-tree
+          ref="checkboxTree"
+          :data="authList"
+          :props="{ label: 'Name', children: 'Children', disabled: 'Disabled' }"
+          :default-expand-all="false"
+          show-checkbox
+          node-key="SysMenuId"
+          :default-checked-keys="defaultCheckedKeys"
+        >
+        </el-tree>
       </div>
-    </div>
-    <div class="shadow-box content-box" v-loading="loading" element-loading-text="loading...">
-      <el-tree
-        ref="checkboxTree"
-        :data="authList"
-        :props="{ label: 'Name', children: 'Children', disabled: 'Disabled' }"
-        :default-expand-all="false"
-        show-checkbox
-        node-key="SysMenuId"
-        :default-checked-keys="defaultCheckedKeys"
-      >
-      </el-tree>
-    </div>
+    </el-card>
   </div>
 </template>
 
@@ -126,9 +115,32 @@ function handleSave(){
 .top-box {
   display: flex;
   justify-content: space-between;
+  border-bottom: #e4e7ed 1px solid;
+
 }
 .content-box {
   margin-top: 20px;
+  height: calc(100vh - 250px);
+  overflow-y: auto;
+  /*修改滚动条样式*/
+  &::-webkit-scrollbar {
+    width: 7px;
+    height: 7px;
+  }
+  &::-webkit-scrollbar-track {
+    background: rgb(239, 239, 239);
+    border-radius: 2px;
+  }
+  &::-webkit-scrollbar-thumb {
+    background: #ccc;
+    border-radius: 10px;
+  }
+  &::-webkit-scrollbar-thumb:hover {
+    background: #888;
+  }
+  &::-webkit-scrollbar-corner {
+    background: #666;
+  }
   .el-tree {
     border-top: 1px solid #e5e7ed;
     border-left: 1px solid #e5e7ed;

+ 45 - 34
src/views/system/RoleList.vue

@@ -1,6 +1,8 @@
 <script setup>
 import { apiSystemRole } from '@/api/system'
+import { useRouter } from 'vue-router'
 
+const router = useRouter()
 
 const roleList = ref([])
 const page = ref(1)
@@ -68,7 +70,9 @@ async function handleDel(e) {
   getRoleList()
 }
 
-
+function handleRoleAdd(params) {
+  router.push({ path: '/system/authSet', query: { ...params } })
+}
 
 
 </script>
@@ -76,40 +80,47 @@ async function handleDel(e) {
 
 <template>
   <div class="system-rolelist-page">
-    <div class="shadow-box top-box">
-      <el-button type="primary" @click="handleEdit('')" v-permission="'role:add'">添加角色</el-button>
-    </div>
+    <el-card>
+      <div class="shadow-box top-box">
+        <el-button type="primary" @click="handleEdit('')" v-permission="'role:add'">添加角色</el-button>
+      </div>
+    </el-card>
     <div class="shadow-box content-box">
-      <el-table
-        :data="roleList"
-        border
-        stripe
-        highlight-current-row
-        element-loading-text="数据加载中..."
-        v-loading="tableLoading"
-      >
-        <!-- <el-table-column prop="SysRoleId" label="序号" /> -->
-        <el-table-column prop="SysRoleName" label="角色" />
-        <el-table-column prop="opt" label="操作">
-          <template #default="{ row }">
-            <el-button v-if="row.SysRoleName!=='admin'" v-permission="'role:edit'" link type="primary" @click="handleEdit(row)"
-              >编辑</el-button
-            >
-            <el-button v-if="row.SysRoleName!=='admin'" v-permission="'role:delete'" link type="danger" @click="handleDel(row)"
-              >删除</el-button
-            >
-          </template>
-        </el-table-column>
-      </el-table>
-      <el-pagination
-        background
-        layout="total,prev,pager,next,jumper"
-        :current-page="page"
-        :page-size="pageSize"
-        :total="totals"
-        @current-change="handlePageChange"
-        style="margin-top: 30px; justify-content: flex-end"
-      />
+      <el-card>
+        <el-table
+          :data="roleList"
+          border
+          stripe
+          highlight-current-row
+          element-loading-text="数据加载中..."
+          v-loading="tableLoading"
+        >
+          <el-table-column prop="SysRoleId" label="序号" />
+          <el-table-column prop="SysRoleName" label="角色" />
+          <el-table-column prop="opt" label="操作">
+            <template #default="{ row }">
+              <el-button v-if="row.SysRoleName!=='admin'" v-permission="permissionBtn.systemManageBtn.role_setting" link type="primary" @click="handleRoleAdd(row)"
+                >权限设置</el-button
+              >
+              <el-button v-if="row.SysRoleName!=='admin'" v-permission="permissionBtn.systemManageBtn.role_convert" link type="primary" @click="handleEdit(row)"
+                >编辑</el-button
+              >
+              <el-button v-if="row.SysRoleName!=='admin'" v-permission="permissionBtn.systemManageBtn.role_delete" link type="danger" @click="handleDel(row)"
+                >删除</el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+        <el-pagination
+          background
+          layout="total,prev,pager,next,jumper"
+          :current-page="page"
+          :page-size="pageSize"
+          :total="totals"
+          @current-change="handlePageChange"
+          style="margin-top: 30px; justify-content: flex-end"
+        />
+      </el-card>
     </div>
   </div>
   <!-- 角色弹窗 -->

+ 103 - 98
src/views/system/userList/Index.vue

@@ -118,107 +118,112 @@ async function changeStatus(e) {
   <div class="flex system-userlist-page">
     <DepartWrap v-model:departActive="departId" @change="refreshUserList" />
     <div class="user-wrap">
-      <div class="user-top-box">
-        <el-button
-          v-permission="'sysUser:add'"
-          type="primary"
-          :icon="Plus"
-          @click="handleAddUser(null)"
-          >添加用户</el-button
-        >
-        <el-input
-          placeholder="姓名/账号/手机号搜索"
-          v-model="keyword"
-          :prefix-icon="Search"
-          clearable
-          @input="refreshUserList"
-          style="max-width: 359px; float: right"
-        >
-        </el-input>
-        <el-select
-          v-model="roleId"
-          placeholder="请选择角色"
-          clearable
-          style="float: right; width: 150px; margin-right: 20px"
-          @change="refreshUserList"
-        >
-          <el-option
-            v-for="item in roleArr"
-            :key="item.SysRoleId"
-            :label="item.SysRoleName"
-            :value="item.SysRoleId"
+      <el-card>
+        <div class="user-top-box">
+          <el-button
+            v-permission="permissionBtn.systemManageBtn.user_add"
+            type="primary"
+            size="large"
+            color="#626aef"
+            @click="handleAddUser(null)"
+            >添加用户</el-button
           >
-          </el-option>
-        </el-select>
-      </div>
+          <el-input
+            placeholder="姓名/账号/手机号搜索"
+            v-model="keyword"
+            :prefix-icon="Search"
+            clearable
+            @input="refreshUserList"
+            style="max-width: 359px; float: right"
+          >
+          </el-input>
+          <el-select
+            v-model="roleId"
+            placeholder="请选择角色"
+            clearable
+            style="float: right; width: 150px; margin-right: 20px"
+            @change="refreshUserList"
+          >
+            <el-option
+              v-for="item in roleArr"
+              :key="item.SysRoleId"
+              :label="item.SysRoleName"
+              :value="item.SysRoleId"
+            >
+            </el-option>
+          </el-select>
+        </div>
+      </el-card>
       <div class="table-wrap">
-        <el-table
-          :data="userList"
-          border
-          stripe
-          highlight-current-row
-          element-loading-text="数据加载中..."
-          v-loading="tableLoading"
-        >
-          <el-table-column
-            v-for="column in tableColOpt"
-            :key="column.key"
-            :prop="column.key"
-            :label="column.label"
+        <el-card>
+          <el-table
+            :data="userList"
+            border
+            stripe
+            highlight-current-row
+            element-loading-text="数据加载中..."
+            v-loading="tableLoading"
           >
-            <template #default="{ row }">
-              <span
-                v-if="column.key === 'IsEnabled'"
-                :style="{ color: !row.IsEnabled ? '#f00' : '' }"
-                >{{ row.IsEnabled ? "启用" : "禁用" }}</span
-              >
-              <span v-else>{{ row[column.key] }}</span>
-            </template>
-          </el-table-column>
-          <el-table-column label="操作" width="260">
-            <template #default="{ row }">
-              <el-button
-                type="primary"
-                v-permission="'sysUser:edit'"
-                link
-                @click.stop="handleAddUser(row)"
-                >编辑</el-button
-              >
-              <el-button
-                v-permission="'sysUser:resetPassword'"
-                type="primary"
-                link
-                @click.stop="openResetPassDialog(row)"
-                >重置密码</el-button
-              >
-              <el-button
-                v-permission="'sysUser:move'"
-                type="primary"
-                link
-                @click.stop="openMoveDepartDialog(row)"
-                >移动分组</el-button
-              >
-              <el-button
-                v-permission="'sysUser:editEnabled'"
-                v-if="row.SysUserName !== 'admin'"
-                :type="row.IsEnabled ? 'danger' : 'primary'"
-                link
-                @click.stop="changeStatus(row)"
-                >{{ row.IsEnabled ? "禁用" : "启用" }}</el-button
-              >
-              <!-- </div> -->
-            </template>
-          </el-table-column>
-        </el-table>
-        <el-pagination
-          background
-          layout="total,prev,pager,next"
-          :current-page="page"
-          :page-size="pageSize"
-          :total="totals"
-          @current-change="handlePageChange"
-          style="margin-top: 30px; justify-content: flex-end"
-        />
+            <el-table-column
+              v-for="column in tableColOpt"
+              :key="column.key"
+              :prop="column.key"
+              :label="column.label"
+            >
+              <template #default="{ row }">
+                <span
+                  v-if="column.key === 'IsEnabled'"
+                  :style="{ color: !row.IsEnabled ? '#f00' : '' }"
+                  >{{ row.IsEnabled ? "启用" : "禁用" }}</span
+                >
+                <span v-else>{{ row[column.key] }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" width="260">
+              <template #default="{ row }">
+                <el-button
+                  type="primary"
+                  v-permission="'sysUser:edit'"
+                  link
+                  @click.stop="handleAddUser(row)"
+                  >编辑</el-button
+                >
+                <el-button
+                  v-permission="'sysUser:resetPassword'"
+                  type="primary"
+                  link
+                  @click.stop="openResetPassDialog(row)"
+                  >重置密码</el-button
+                >
+                <el-button
+                  v-permission="'sysUser:move'"
+                  type="primary"
+                  link
+                  @click.stop="openMoveDepartDialog(row)"
+                  >移动分组</el-button
+                >
+                <el-button
+                  v-permission="'sysUser:editEnabled'"
+                  v-if="row.SysUserName !== 'admin'"
+                  :type="row.IsEnabled ? 'danger' : 'primary'"
+                  link
+                  @click.stop="changeStatus(row)"
+                  >{{ row.IsEnabled ? "禁用" : "启用" }}</el-button
+                >
+                <!-- </div> -->
+              </template>
+            </el-table-column>
+          </el-table>
+          <el-pagination
+            background
+            layout="total,prev,pager,next"
+            :current-page="page"
+            :page-size="pageSize"
+            :total="totals"
+            @current-change="handlePageChange"
+            style="margin-top: 30px; justify-content: flex-end"
+          />
+        </el-card>
       </div>
     </div>
   </div>

+ 88 - 87
src/views/system/userList/components/DepartWrap.vue

@@ -231,97 +231,99 @@ function getFormTitle(e) {
 </script>
 
 <template>
-  <div class="depart-tree-wrap">
-    <div class="company_top" @click="initDepart">
-      <span>部门管理</span>
-    </div>
-    <el-button
-      v-permission="'department:add'"
-      type="primary"
-      block
-      :icon="Plus"
-      @click="
-        handleDepartOpt(
-          {},
-          { Level: 1, SysDepartmentId: 0, SysDepartmentName: '' },
-          'add'
-        )
-      "
-      >添加部门</el-button
-    >
-    <div class="tree-wrap">
-      <el-tree
-        class="depart_tree"
-        :data="departOpts"
-        :props="departTreeKeys"
-        :current-node-key="departActive"
-        :draggable="hasPermission('department:move')"
-        check-on-click-node
-        :expand-on-click-node="false"
-        node-key="SysDepartmentId"
-        check-strictly
-        highlight-current
-        empty-text="暂无部门"
-        @current-change="handleDepartActiveChange"
-        :allow-drop="allowDrop"
-        :allow-drag="allowDrag"
-        @node-drop="handleDropOver"
+  <el-card>
+    <div class="depart-tree-wrap">
+      <div class="company_top" @click="initDepart">
+        <span>部门管理</span>
+      </div>
+      <el-button
+        v-permission="permissionBtn.systemManageBtn.user_addDept"
+        type="primary"
+        color="#626aef"
+        block
+        @click="
+          handleDepartOpt(
+            {},
+            { Level: 1, SysDepartmentId: 0, SysDepartmentName: '' },
+            'add'
+          )
+        "
+        >添加部门</el-button
       >
-        <template #default="{ node, data }">
-          <div class="depart-item-box">
-            <div class="label">{{ node.label }}</div>
-            <div class="opt-box" v-show="showClassifyOpt(node, data)" v-if="node.label === '营业部'">
-              <el-dropdown>
-                <svg-icon
-                  name="menu"
-                  size="16px"
-                  style="margin-right: 10px"
-                ></svg-icon>
-                <template #dropdown>
-                  <el-dropdown-menu>
-                    <el-dropdown-item
-                      v-if="node.level < 3&&hasPermission('department:add')"
-                      @click.stop="handleDepartOpt(node, data, 'add')"
-                      >添加部门分组</el-dropdown-item
-                    >
-                  </el-dropdown-menu>
-                </template>
-              </el-dropdown>
-            </div>
-            <div class="opt-box" v-show="showClassifyOpt(node, data)" v-else>
-              <svg-icon
-                name="edit2"
-                size="16px"
-                v-if="hasPermission('department:edit')"
-                @click.stop="handleDepartOpt(node, data, 'edit')"
-              ></svg-icon>
-              <el-dropdown>
+      <div class="tree-wrap">
+        <el-tree
+          class="depart_tree"
+          :data="departOpts"
+          :props="departTreeKeys"
+          :current-node-key="departActive"
+          :draggable="hasPermission('department:move')"
+          check-on-click-node
+          :expand-on-click-node="false"
+          node-key="SysDepartmentId"
+          check-strictly
+          highlight-current
+          empty-text="暂无部门"
+          @current-change="handleDepartActiveChange"
+          :allow-drop="allowDrop"
+          :allow-drag="allowDrag"
+          @node-drop="handleDropOver"
+        >
+          <template #default="{ node, data }">
+            <div class="depart-item-box">
+              <div class="label">{{ node.label }}</div>
+              <div class="opt-box" v-show="showClassifyOpt(node, data)" v-if="node.label === '营业部'">
+                <el-dropdown>
+                  <svg-icon
+                    name="menu"
+                    size="16px"
+                    style="margin-right: 10px"
+                  ></svg-icon>
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item
+                        v-if="node.level < 3&&hasPermission(permissionBtn.systemManageBtn.user_addDept)"
+                        @click.stop="handleDepartOpt(node, data, 'add')"
+                        >添加部门分组</el-dropdown-item
+                      >
+                    </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+              </div>
+              <div class="opt-box" v-show="showClassifyOpt(node, data)" v-else>
                 <svg-icon
-                  name="menu"
+                  name="edit2"
                   size="16px"
-                  style="margin-right: 10px"
+                  v-if="hasPermission('department:edit')"
+                  @click.stop="handleDepartOpt(node, data, 'edit')"
                 ></svg-icon>
-                <template #dropdown>
-                  <el-dropdown-menu>
-                    <el-dropdown-item
-                      v-if="hasPermission('department:delete')"
-                      @click.stop="handleDepartOpt(node, data, 'del')"
-                      >删除部门</el-dropdown-item
-                    >
-                    <el-dropdown-item
-                      v-if="node.level < 3&&hasPermission('department:add')"
-                      @click.stop="handleDepartOpt(node, data, 'add')"
-                      >添加部门分组</el-dropdown-item
-                    >
-                  </el-dropdown-menu>
-                </template>
-              </el-dropdown>
+                <el-dropdown>
+                  <svg-icon
+                    name="menu"
+                    size="16px"
+                    style="margin-right: 10px"
+                  ></svg-icon>
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item
+                        v-if="hasPermission(permissionBtn.systemManageBtn.user_deleteDept)"
+                        @click.stop="handleDepartOpt(node, data, 'del')"
+                        >删除部门</el-dropdown-item
+                      >
+                      <el-dropdown-item
+                        v-if="node.level < 3&&hasPermission(permissionBtn.systemManageBtn.user_addDept)"
+                        @click.stop="handleDepartOpt(node, data, 'add')"
+                        >添加部门分组</el-dropdown-item
+                      >
+                    </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+              </div>
             </div>
-          </div>
-        </template>
-      </el-tree>
+          </template>
+        </el-tree>
+      </div>
     </div>
-  </div>
+  </el-card>
   <!-- 新增一级部分弹窗 -->
   <el-dialog v-model="showEditDepart" width="500" draggable>
     <template #header>
@@ -395,9 +397,8 @@ function getFormTitle(e) {
   background-color: #fff;
   min-width: 200px;
   width: 16%;
-  padding: 20px;
   border-radius: 4px;
-  height: calc(100vh - 120px);
+  height: calc(100vh - 165px);
   display: flex;
   flex-direction: column;
   .company_top {

+ 2 - 1
vite.config.js

@@ -95,7 +95,8 @@ export default defineConfig(({ mode }) => {
       port: 8706,
       proxy: {
         "/v1": {
-          target: "http://8.136.199.33:8705/adminapi",
+          // target: "http://8.136.199.33:8705/adminapi",
+          target: "http://192.168.77.34:8706/adminapi",
           changeOrigin: true,
           rewrite: (path) => path.replace(/^\/v1/, ""),
         },