Explorar o código

Merge branch 'v2.0' into v2.0_ch

chenlei hai 3 semanas
pai
achega
94a723bd20

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

@@ -0,0 +1,6 @@
+import apiCustomerUser from './user'
+
+export {
+  apiCustomerUser
+}
+

+ 37 - 0
src/api/customer/user.js

@@ -0,0 +1,37 @@
+import {get,post} from '@/api/index'
+
+export default{
+	// 用户列表
+  userList:params=>{
+    return get('/eta_business/user/list',params)
+  },
+  // 新增用户
+  addUser:params=>{
+    return post('/eta_business/user/add',params)
+  },
+  // 编辑用户
+  editUser:params=>{
+    return post('/eta_business/user/edit',params)
+  },
+  // 删除用户
+  deleteUser:params=>{
+    return post('/eta_business/user/delete',params)
+  },
+  // 启用\禁用用户
+  enableChange:params=>{
+    return post('/eta_business/user/editEnabled',params)
+  },
+  // 移动用户至新商户
+  moveUser:params=>{
+    return post('/eta_business/user/changeBusiness',params)
+  },
+  // 获取批量导入用户的数据
+  getImportUserList:params=>{
+    return post('/eta_business/user/import/list',params)
+  },
+  // 导入用户
+  importUser:params=>{
+    return post('/eta_business/user/import',params)
+  }
+
+}

+ 5 - 1
src/api/modules/businessCustom.js

@@ -20,6 +20,10 @@ export const businessCustomInterence = {
     getBusinessList:(params)=>{
         return get('/eta_business/page_list',params)
     },
+    // 商家列表 (不分页)
+    bussinessListAll:params=>{
+        return get('/eta_business/list',params)
+    },
     /**
      * 获取商家签约列表
      * @param EtaBusinessId Integer 商家ID
@@ -156,5 +160,5 @@ export const businessCustomInterence = {
      */
     setConfigList:(params)=>{
         return post('/eta_business/api/config/set',params)
-    }
+    },
 }

+ 19 - 0
src/api/system/common.js

@@ -8,5 +8,24 @@ export default{
 	// 系统菜单
 	menuList:()=>{
 		return get('/system/menu/list',{})
+	},
+	// 手机号区号
+	mobileAreaCode:()=>{
+		return get('/eta_business/area_code/list',{})
+	},
+	/**
+	 * 获取系统角色
+	 * @param RoleLevel 部门管理菜单->添加用户->查询所有角色列表时,需传入RoleLevel:0
+	 */
+	getRoleList:params=>{
+		return get('/system/role/all',params)
+	},
+	// 获取角色对应的菜单数据
+	getRoleMenuList:params=>{
+		return get('/system/role/menu/list',params)
+	},
+	// 设置角色菜单权限
+	setRoleMenuData:params=>{
+		return post('/system/role/menu/add',params)
 	}
 }

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

@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.5 12.4997V13.7497H12.5V12.4997H7.5Z" fill="currentColor"/>
+<path d="M5.625 6.23828V7.49971H3.75C3.40482 7.49971 3.125 7.77953 3.125 8.12471V16.8747C3.125 17.2199 3.40482 17.4997 3.75 17.4997H16.25C16.5952 17.4997 16.875 17.2199 16.875 16.8747V8.12471C16.875 7.77953 16.5952 7.49971 16.25 7.49971H14.375V6.23828C14.375 3.82204 12.4162 1.86328 10 1.86328C7.58375 1.86328 5.625 3.82204 5.625 6.23828ZM13.125 7.49971H6.875V6.23828C6.875 4.51239 8.27411 3.11328 10 3.11328C11.7259 3.11328 13.125 4.51239 13.125 6.23828V7.49971ZM4.375 8.74971H15.625V16.2497H4.375V8.74971Z" fill="currentColor"/>
+</svg>

+ 75 - 0
src/components/SelectBusiness.vue

@@ -0,0 +1,75 @@
+<script setup>
+import {businessCustomInterence} from '@/api/modules/businessCustom'
+
+const value=defineModel('value')
+const emits=defineEmits(['change'])
+
+const props=defineProps({
+  placeholder:{
+    type:String,
+    default:'请输入搜索'
+  },
+  multiple:{
+    type:Boolean,
+    default:false,
+  },
+  filterable:{
+    type:Boolean,
+    default:false,
+  },
+  clearable:{
+    type:Boolean,
+    default:false,
+  },
+  disabled:{
+    type:Boolean,
+    default:false,
+  }
+})
+
+const options=ref([])
+const loading=ref(false)
+
+async function remoteMethod(search){
+  loading.value=true
+  const res=await businessCustomInterence.bussinessListAll({
+    Keyword:search
+  })
+  loading.value=false
+  if(res.Ret!=200) return
+  options.value=res.Data.List||[]
+}
+
+// 默认获取一次
+remoteMethod('')
+
+function handleChange(value,context){
+  emits('change',value,context)
+}
+
+</script>
+
+<template>
+  <t-select
+    v-model="value"
+    :multiple="props.multiple"
+    :filterable="props.filterable"
+    :placeholder="props.placeholder"
+    :clearable="props.clearable"
+    :loading="loading"
+    :disabled="props.disabled"
+    @search="remoteMethod"
+    @change="handleChange"
+  >
+    <t-option 
+      v-for="item in options" 
+      :key="item.BusinessCode" 
+      :value="item.BusinessCode" 
+      :label="item.BusinessName"
+    />
+  </t-select>
+</template>
+
+<style lang="scss" scoped>
+
+</style>

+ 1 - 0
src/layout/components/LeftWrap.vue

@@ -61,6 +61,7 @@ function getMenuIcon(item) {
     '培训管理':'menu/menu06',
     '个性化设置':'menu/menu07',
     '系统设置':'menu/menu08',
+    '权限配置':'menu/menu09'
   }
   return iconMap[item] || 'menu/setting'
 

+ 1 - 1
src/plugin/dialog.jsx

@@ -5,7 +5,7 @@ import warningIcon from '@/assets/icons/warning.png'
 export function $confirmDialog(props){
   const headerHtml=()=><div style="display:flex;align-items:center">
     <img src={warningIcon} style="width:20px" />
-    <span>{props.header}</span>
+    <span>{props.header||'提示'}</span>
   </div>
   return new Promise((resolve,reject)=>{
     const confirmDia = DialogPlugin.confirm({

+ 40 - 0
src/router/modules/system.js

@@ -0,0 +1,40 @@
+import LayoutIndex from "@/layout/Index.vue";
+
+export default[
+  {
+    path:'/system',
+    name:'SystemRole',
+    component:LayoutIndex,
+    meta:{
+      title:'权限配置'
+    },
+    children:[
+      {
+        path:'roleMenuAuth',
+        name:'SystemRoleMenuAuth',
+        component:()=>import('@/views/system/RoleMenuAuth.vue'),
+        meta:{
+          title:'权限配置'
+        },
+      },
+    ]
+  },
+  {
+    path:'/system',
+    name:'SystemSet',
+    component:LayoutIndex,
+    meta:{
+      title:'个性化设置'
+    },
+    children:[
+      {
+        path:'commonSet',
+        name:'SystemCommonSet',
+        component:()=>import('@/views/system/CommonSet.vue'),
+        meta:{
+          title:'个性化设置'
+        },
+      },
+    ]
+  }
+]

+ 4 - 0
src/styles/common.scss

@@ -28,6 +28,10 @@ img {
     -ms-interpolation-mode: nearest-neighbor;
 }
 
+ul li{
+    list-style: none;
+}
+
 .flex{
     display: flex;
 }

+ 15 - 2
src/views/AutoLogin.vue

@@ -1,10 +1,23 @@
 <script setup>
-import {apiSystemSet} from '@/api/system'
+import {apiSystemSet,apiSystemCommon} from '@/api/system'
 import { useRoute, useRouter } from 'vue-router'
 
 const route=useRoute()
 const router=useRouter()
 
+// 获取有菜单跳转
+async function handleNavigation(){
+    const res=await apiSystemCommon.menuList()
+    if(res.Ret!==200) return
+    const arr=res.Data.List||[]
+    if(arr.length===0){
+        MessagePlugin.waring('无任何菜单权限,请联系管理员')
+        return
+    }
+    const path=arr[0].children[0].path
+    router.replace(path)
+}
+
 function init(){
     const code=route.query.code
     if(!code) return
@@ -14,7 +27,7 @@ function init(){
         if(res.Ret===200){
             sessionStorage.setItem('token',res.Data.Authorization)
             sessionStorage.setItem('userInfo',JSON.stringify(res.Data))
-            router.replace('/etaChart/index')
+            handleNavigation()
         }
     })
 }

+ 0 - 48
src/views/customer/components/SelectETACustomer.vue

@@ -1,48 +0,0 @@
-<script setup>
-
-const emits=defineEmits(['change'])
-
-const value = defineModel('value');
-const options = ref([]);
-const loading = ref(false);
-
-function remoteMethod (search) {
-
-    loading.value = true;
-    setTimeout(() => {
-      loading.value = false;
-      options.value = [
-        {
-          value: `腾讯_test1`,
-          label: `腾讯_test1`,
-        },
-        {
-          value: `腾讯_test2`,
-          label: `腾讯_test2`,
-        },
-        {
-          value: `腾讯_test3`,
-          label: `腾讯_test3`,
-        },
-      ];
-    }, 500);
-  
-};
-
-function handleChange(value,context){
-  emits('change',value,context)
-}
-
-</script>
-
-<template>
-  <t-select
-    v-model="value"
-    filterable
-    placeholder="输入社会信用码或客户名称"
-    :loading="loading"
-    :options="options"
-    @search="remoteMethod"
-    @change="handleChange"
-  />
-</template>

+ 140 - 40
src/views/customer/user/Index.vue

@@ -1,25 +1,28 @@
 <script setup>
 import { SearchIcon } from 'tdesign-icons-vue-next';
 import EditUser from './components/EditUser.vue'
+import MoveUser from './components/MoveUser.vue'
+import ConfirmImportUser from './components/ConfirmImportUser.vue'
+import {apiCustomerUser} from '@/api/customer'
 
 const jobOpts = [
   {
     label: '在职',
-    value: '在职'
+    value: 1
   },
   {
     label: '离职',
-    value: '离职'
+    value: 0
   }
 ]
 const accountStatusOpts = [
   {
     label: '启用',
-    value: '启用'
+    value: 1
   },
   {
     label: '禁用',
-    value: '禁用'
+    value: 0
   }
 ]
 
@@ -31,29 +34,99 @@ const filterState = reactive({
 })
 const tableData = ref([])
 const columns = [
-  { align: 'center', colKey: '', title: '姓名' },
-  { align: 'center', colKey: '', title: '手机号' },
-  { align: 'center', colKey: '', title: '岗位-部门' },
-  { align: 'center', colKey: '', title: '最近登录时间', sorter: true, },
-  { align: 'center', colKey: '', title: '在职状态' },
-  { align: 'center', colKey: '', title: '账号状态' },
-  { align: 'center', colKey: '', title: '客户名称' },
+  { align: 'center', colKey: 'RealName', title: '姓名' },
+  { align: 'center', colKey: 'Mobile', title: '手机号',width:'150px' },
+  { align: 'center', colKey: 'DepartmentName', title: '岗位-部门',width:'150px' },
+  { align: 'center', colKey: 'LastLoginTime', title: '最近登录时间',width:'180px', sorter: true, },
+  { align: 'center', colKey: 'PositionStatus', title: '在职状态',width:'100px' },
+  { align: 'center', colKey: 'Enabled', title: '账号状态',width:'100px' },
+  { align: 'center', colKey: 'BusinessName', title: '客户名称' },
   {
     align: 'center',
     colKey: 'opt',
     title: '操作',
   },
 ]
-const tablePagination = {
-  defaultCurrent: 1,
-  defaultPageSize: 20,
+const tablePagination = ref({
+  current: 1,
+  pageSize: 20,
   total: 0,
   showPageSize:false
+})
+async function getUserList(){
+  const res=await apiCustomerUser.userList({
+    PageSize:tablePagination.pageSize,
+    CurrentIndex:tablePagination.current,
+    PositionStatus:filterState.jobStatus===''?-1:filterState.jobStatus,
+    Enabled:filterState.accountStatus===''?-1:filterState.accountStatus,
+    Keyword:filterState.keyword,
+    BusinessCode:filterState.customer
+  })
+  if(res.Ret!==200) return
+  const arr=res.Data.List||[]
+  tableData.value=arr
+  tablePagination.value.total=res.Data.Paging.Totals
+}
+getUserList()
+
+function handleRefreshList(){
+  tablePagination.value.current=1
+  tableData.value=[]
+  getUserList()
 }
 
+const editUserData=ref(null)
 
 const showEditUser=ref(false)
+function handleEditUser(data){
+  editUserData.value=data
+  showEditUser.value=true
+}
 
+const showMoveUser=ref(false)
+function handleMoveUser(data){
+  editUserData.value=data
+  showMoveUser.value=true
+}
+
+// 删除用户
+async function handleDelUser(item){
+  await $confirmDialog({
+    body:'删除后该用户将不能访问ETA社区,是否确认删除?',
+    confirmBtn:{default:'确认',theme:'danger'},
+  })
+  const res=await apiCustomerUser.deleteUser({
+    UserId:item.UserId
+  })
+  if(res.Ret!=200) return
+  MessagePlugin.success('删除成功')
+  handleRefreshList()
+}
+
+// 启用禁用客户
+async function handleEnableUserChange(item,type){
+  const res=await apiCustomerUser.enableChange({
+    UserId:item.UserId,
+    Enabled:type
+  })
+  if(res.Ret!=200) return
+  MessagePlugin.success('操作成功')
+  item.Enabled=type
+}
+
+
+// 导入用户
+const showConfirmImportUser=ref(false)
+const confirmImportUserData=ref([])
+async function handleImportUser(e){
+  confirmImportUserData.value=[]
+  const data=new FormData()
+  data.append("File", e.raw)
+  const res=await apiCustomerUser.getImportUserList(data)
+  if(res.Ret!==200) return
+  showConfirmImportUser.value=true
+  confirmImportUserData.value=res.Data.ValidUser||[]
+}
 
 
 </script>
@@ -61,12 +134,22 @@ const showEditUser=ref(false)
 <template>
   <div class="customer-userlist-page">
     <div class="bg-white flex top-wrap">
-      <t-button style="width: 120px" @click="showEditUser=true">新增用户</t-button>
-      <t-button style="width: 120px; margin-left: 10px">批量导入用户</t-button>
+      <t-button style="width: 120px" @click="showEditUser=true;editUserData=null">新增用户</t-button>
+      <t-upload
+        :request-method="handleImportUser"
+        theme="custom"
+        accept=".xls,.xlsx"
+      >
+        <t-button style="width: 120px; margin-left: 10px">批量导入用户</t-button>
+      </t-upload>
+
       <t-button style="width: 120px; margin-left: 10px" theme="primary" variant="text">下载导入模板</t-button>
       <t-input
         style="width: 310px; margin-left: auto"
         placeholder="姓名/手机号"
+        v-model="filterState.keyword"
+        clearable
+        @change="handleRefreshList"
       >
         <template #prefixIcon><SearchIcon /></template>
       </t-input>
@@ -78,11 +161,12 @@ const showEditUser=ref(false)
           v-model:value="filterState.jobStatus"
           clearable
           style="width: 240px"
+          @change="handleRefreshList"
         >
           <t-option
             v-for="item in jobOpts"
             :key="item.value"
-            :label="item.value"
+            :label="item.label"
             :value="item.value"
           />
         </t-select>
@@ -91,30 +175,26 @@ const showEditUser=ref(false)
           v-model:value="filterState.accountStatus"
           clearable
           style="width: 240px"
+          @change="handleRefreshList"
         >
           <t-option
             v-for="item in accountStatusOpts"
             :key="item.value"
-            :label="item.value"
+            :label="item.label"
             :value="item.value"
           />
         </t-select>
-        <t-select
-          placeholder="客户名称"
-          v-model:value="filterState.customer"
-          clearable
+        <select-business 
+          placeholder="客户名称" 
+          clearable 
+          filterable
+          v-model="filterState.customer" 
           style="width: 240px"
-        >
-          <!-- <t-option
-            v-for="item in jobOpts"
-            :key="item.value"
-            :label="item.value"
-            :value="item.value"
-          /> -->
-        </t-select>
+          @change="handleRefreshList"
+        />
       </div>
       <t-table
-        rowKey="id"
+        rowKey="UserId"
         :data="tableData"
         :columns="columns"
         bordered
@@ -122,20 +202,40 @@ const showEditUser=ref(false)
         show-header
         resizable
       >
-        <template #cellEmptyContent="{ col }">
-          <div v-if="col.colKey === 'opt'">
-            <t-button size="small" variant="text" theme="primary">编辑</t-button>
-            <t-button size="small" variant="text" theme="primary">启用</t-button>
-            <t-button size="small" variant="text" theme="danger">禁用</t-button>
-            <t-button size="small" variant="text" theme="primary">移动</t-button>
-            <t-button size="small" variant="text" theme="danger">删除</t-button>
-          </div>
+        <template #Mobile="{ row }">
+          <span>{{row.CountryCode}}-{{row.Mobile}}</span>
+        </template>
+        <template #DepartmentName="{ row }">
+          <span>{{row.Position}}-{{row.DepartmentName}}</span>
+        </template>
+        <template #PositionStatus="{ row }">
+          <t-tag 
+            :theme="row.PositionStatus?'success':'danger'"
+            variant="light"
+          >{{row.PositionStatus?'在职':'离职'}}</t-tag>
+        </template>
+        <template #Enabled="{ row }">
+          <t-tag 
+            :theme="row.Enabled?'success':'danger'"
+            variant="light"
+          >{{row.PositionStatus?'已启用':'已禁用'}}</t-tag>
+        </template>
+        <template #opt="{ row }">
+          <t-button size="small" variant="text" theme="primary" @click="handleEditUser(row)">编辑</t-button>
+          <t-button size="small" variant="text" theme="danger" v-if="row.Enabled" @click="handleEnableUserChange(row,0)">禁用</t-button>
+          <t-button size="small" variant="text" theme="primary" v-else @click="handleEnableUserChange(row,1)">启用</t-button>
+          <t-button size="small" variant="text" theme="primary" @click="handleMoveUser(row)">移动</t-button>
+          <t-button size="small" variant="text" theme="danger" @click="handleDelUser(row)">删除</t-button>
         </template>
       </t-table>
     </div>
   </div>
   <!-- 新增\编辑用户 -->
-  <EditUser v-model:show="showEditUser"/>
+  <EditUser v-model:show="showEditUser" :data="editUserData" @change="handleRefreshList"/>
+  <!-- 移动用户 -->
+  <MoveUser v-model:show="showMoveUser" :data="editUserData" @change="handleRefreshList"/>
+  <!-- 确认批量导入的用户 -->
+  <ConfirmImportUser v-model:show="showConfirmImportUser" :data="confirmImportUserData"/>
 </template>
 
 <style lang="scss" scoped>

+ 2 - 2
src/views/customer/user/components/ActionStatisticForCustomer.vue

@@ -1,5 +1,4 @@
 <script setup>
-import SelectETACustomer from '../../components/SelectETACustomer.vue'
 import FavChartStatistic from './FavChartStatistic.vue'
 import { Calendar1Icon } from 'tdesign-icons-vue-next'
 
@@ -23,6 +22,7 @@ const timeType = [
 ]
 const timeTypeValue = ref('')
 const selectDate = ref([])
+const selectBusinessValue=ref('')
 
 const tableData = ref([])
 const columns = [
@@ -44,7 +44,7 @@ const showFavChart=ref(false)
 
 <template>
   <div class="flex top-filter">
-    <SelectETACustomer style="width: 240px; margin-right: 50px" />
+    <select-business placeholder="输入社会信用码或客户名称" filterable v-model="selectBusinessValue" style="width: 240px; margin-right: 50px" />
     <t-button
       :variant="timeTypeValue === item.value ? 'base' : 'outline'"
       v-for="item in timeType"

+ 81 - 0
src/views/customer/user/components/ConfirmImportUser.vue

@@ -0,0 +1,81 @@
+<script setup>
+import {apiCustomerUser} from '@/api/customer'
+
+const show = defineModel('show', { type: Boolean, default: false })
+const props=defineProps({
+  data:{
+    type:Array,
+    default:()=>[]
+  }
+})
+
+const columns = [
+  { align: 'center', colKey: 'RealName', title: '姓名' },
+  { align: 'center', colKey: 'Mobile', title: '手机号',width:'150px' },
+  { align: 'center', colKey: 'DepartmentName', title: '岗位-部门',width:'150px' },
+  { align: 'center', colKey: 'BusinessName', title: '客户名称' },
+  { align: 'center', colKey: 'PositionStatus', title: '在职状态',width:'100px' }, 
+]
+
+async function handleSave(){
+  const res=await apiCustomerUser.importUser({ValidUser:props.data})
+  if(res.Ret!==200) return
+  MessagePlugin.success('导入成功')
+  show.value=false
+}
+
+</script>
+<template>
+  <t-dialog
+    v-model:visible="show"
+    header="批量导入"
+    draggable
+    attach="body"
+    top="50px"
+    width="80%"
+    :cancelBtn="null"
+    :confirmBtn="null"
+    class="import-user-wrap"
+  >
+    <t-table
+      rowKey="UserId"
+      :data="props.data"
+      :columns="columns"
+      bordered
+      max-height="500"
+      show-header
+      resizable
+    >
+      <template #Mobile="{ row }">
+        <span>{{row.CountryCode}}-{{row.Mobile}}</span>
+      </template>
+      <template #DepartmentName="{ row }">
+        <span>{{row.Position}}-{{row.DepartmentName}}</span>
+      </template>
+      <template #PositionStatus="{ row }">
+        <t-tag 
+          :theme="row.PositionStatus?'success':'danger'"
+          variant="light"
+        >{{row.PositionStatus?'在职':'离职'}}</t-tag>
+      </template>
+    </t-table>
+    <template #footer>
+      <div class="bottom-btn">
+        <t-button theme="default" @click="show=false">取消</t-button>
+        <t-button type="submit" @click="handleSave">确定</t-button>
+      </div>
+    </template>
+  </t-dialog>
+</template>
+
+<style lang="scss" scoped>
+.import-user-wrap{
+  .bottom-btn{
+    margin-top: 60px;
+    text-align: center;
+    .t-button{
+      width: 120px;
+    }
+  }
+}
+</style>

+ 53 - 12
src/views/customer/user/components/EditUser.vue

@@ -1,8 +1,11 @@
 <script setup>
 import { useTemplateRef, watch } from "vue";
+import {apiSystemCommon} from '@/api/system'
+import {apiCustomerUser} from '@/api/customer'
 
 
 const show = defineModel('show', { type: Boolean, default: false })
+const emits=defineEmits(['change'])
 const props=defineProps({
   data:{
     type:[null,Object],
@@ -10,16 +13,22 @@ const props=defineProps({
   }
 })
 
-const telCodeOpts=['86']
+const telCodeOpts=ref([])
+async function getMobileAreaCode(){
+  const res=await apiSystemCommon.mobileAreaCode()
+  if(res.Ret!=200) return
+  telCodeOpts.value=res.Data||[]
+  formData.telCode=telCodeOpts.value[0]?.Value
+}
 
 const jobStatusOpts=[
   {
     label:'在职',
-    value:'在职'
+    value:1
   },
   {
     label:'离职',
-    value:'离职'
+    value:0
   }
 ]
 
@@ -27,12 +36,13 @@ const FORM_RULES = {
   name: [{ required: true, message: '请输入姓名' }],
   tel:[{ required: true, message: '请输入手机号' }],
   jobStatus:[{ required: true, message: '请选择在职状态' }],
+  customer:[{ required: true, message: '请选择所属客户' }]
 };
 
 const formIns=useTemplateRef('formIns')
 const formData=reactive({
   name:'',
-  telCode:'86',
+  telCode:'',
   tel:'',
   customer:'',
   post:'',
@@ -43,7 +53,23 @@ const formData=reactive({
 async function handleSave(){
   const validRes=await formIns.value.validate()
   if(validRes!==true) return
-
+  const params={
+    RealName:formData.name,
+    CountryCode:formData.telCode,
+    Mobile:formData.tel,
+    Position:formData.post,
+    BusinessCode:formData.customer,
+    DepartmentName:formData.depart,
+    PositionStatus:formData.jobStatus
+  }
+  const res=props.data?await apiCustomerUser.editUser({
+    ...params,
+    UserId:props.data.UserId
+  }):await apiCustomerUser.addUser(params)
+  if(res.Ret!=200) return
+  show.value=false
+  MessagePlugin.success(props.data?'保存成功':'新增成功')
+  emits('change')
 }
 
 
@@ -54,8 +80,17 @@ watch(
       formIns.value.reset()
       return
     }
-    if(n&&props.data){
-
+    if(n){
+      getMobileAreaCode()
+      if(props.data){
+        formData.name=props.data.RealName
+        formData.telCode=props.data.CountryCode
+        formData.tel=props.data.Mobile
+        formData.customer=props.data.BusinessCode
+        formData.post=props.data.Position
+        formData.depart=props.data.DepartmentName
+        formData.jobStatus=props.data.PositionStatus
+      }
     }
   }
 )
@@ -85,18 +120,24 @@ watch(
         <t-input v-model="formData.name" placeholder="请输入姓名"></t-input>
       </t-form-item>
       <t-form-item label="手机号" name="tel">
-        <t-select v-model:value="formData.telCode" style="width:80px">
+        <t-select v-model:value="formData.telCode" style="width:80px;margin-right:10px">
           <t-option
             v-for="item in telCodeOpts"
-            :key="item"
-            :label="item"
-            :value="item"
+            :key="item.Value"
+            :label="item.Name"
+            :value="item.Value"
           />
         </t-select>
         <t-input v-model="formData.tel" placeholder="请输入手机号"></t-input>
       </t-form-item>
       <t-form-item label="所属客户" name="customer">
-        
+        <select-business 
+          placeholder="输入社会信用码或客户名称"
+          filterable
+          :disabled="props.data?true:false"
+          v-model="formData.customer"
+          v-if="show"
+        />
       </t-form-item>
       <t-form-item label="岗位" name="post">
         <t-input v-model="formData.post" placeholder="请输入岗位"></t-input>

+ 22 - 5
src/views/customer/user/components/MoveUser.vue

@@ -1,8 +1,9 @@
 <script setup>
 import { useTemplateRef, watch } from "vue";
-
+import {apiCustomerUser} from '@/api/customer'
 
 const show = defineModel('show', { type: Boolean, default: false })
+const emits=defineEmits(['change'])
 const props=defineProps({
   data:{
     type:[null,Object],
@@ -11,7 +12,7 @@ const props=defineProps({
 })
 
 const FORM_RULES = { 
-  company: [{ required: true, message: '请输入姓名' }],
+  company: [{ required: true, message: '请选择客户' }],
 };
 
 const formIns=useTemplateRef('formIns')
@@ -22,7 +23,14 @@ const formData=reactive({
 async function handleSave(){
   const validRes=await formIns.value.validate()
   if(validRes!==true) return
-
+  const res=await apiCustomerUser.moveUser({
+    UserId:props.data.UserId,
+    BusinessCode:formData.company
+  })
+  if(res.Ret!==200) return
+  show.value=false
+  MessagePlugin.success('移动成功')
+  emits('change')
 }
 
 
@@ -58,11 +66,20 @@ watch(
       labelAlign="top"
     >
       <t-form-item label="移动到" name="company">
-        <t-input v-model="formData.company" placeholder="请选择公司"></t-input>
+        <select-business 
+          v-model="formData.company"
+          placeholder="输入社会信用码或客户名称"
+          filterable
+        />
       </t-form-item>
       
       <t-form-item label="所属客户" name="customer">
-        
+        <select-business 
+          :value="props.data?.BusinessCode"
+          placeholder="输入社会信用码或客户名称"
+          disabled
+          v-if="show"
+        />
       </t-form-item>
     </t-form>
     <template #footer>

+ 35 - 0
src/views/system/CommonSet.vue

@@ -0,0 +1,35 @@
+<script setup>
+
+const chartWaterImgs=ref([])
+async function handleUploadImg(e){
+  const file=e.raw
+}
+
+</script>
+
+<template>
+  <div class="bg-white common-set-page">
+    <h3>设置图表水印</h3>
+    <t-upload
+      v-model="chartWaterImgs"
+      theme="image"
+      tips="上传格式:png、jpg"
+      accept="image/png,image/jpeg"
+      :request-method="handleUploadImg"
+      :locale="{
+        triggerUploadText: {
+          image: '点击上传图片',
+        },
+      }"
+    />
+    <t-button style="margin-top:30px">应用到全部社区图表</t-button>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.common-set-page{
+  padding: 20px;
+  border-radius: 4px;
+  height: calc(100vh - 160px);
+}
+</style>

+ 111 - 0
src/views/system/RoleMenuAuth.vue

@@ -0,0 +1,111 @@
+<script setup>
+import {apiSystemCommon} from '@/api/system'
+
+// 获取角色对应的菜单数据
+const menuList=ref([])
+async function getMenuList(){
+  menuList.value=[]
+  const res=await apiSystemCommon.getRoleMenuList({
+    RoleId:roleId.value
+  })
+  if(res.Ret!==200) return
+  menuList.value=res.Data.List||[]
+}
+
+const roleId=ref('')
+const roleOpts=ref([])
+async function getRoleOpts(){
+  const res=await apiSystemCommon.getRoleList({RoleLevel:0})
+  if(res.Ret!==200) return
+  roleOpts.value=res.Data.List||[]
+  roleId.value=roleOpts.value[0]?.RoleId
+  getMenuList()
+}
+getRoleOpts()
+
+async function handleSave(){
+  let arr=[]
+  menuList.value.forEach(item => {
+    arr=[...arr,...item.CheckList]
+  });
+  const res=await apiSystemCommon.setRoleMenuData({
+    MenuIdStr:arr.join(','),
+    RoleId:roleId.value
+  })
+  if(res.Ret!==200) return
+  MessagePlugin.success('保存成功')
+}
+
+</script>
+
+<template>
+  <div class="role-menu-auth-page">
+    <div class="bg-white flex top-wrap">
+      <span style="flex-shrink: 0;">角色</span>
+      <t-select placeholder="请选择角色" v-model="roleId" style="width:240px" @change="getMenuList">
+        <t-option
+          v-for="item in roleOpts"
+          :key="item.RoleId"
+          :label="item.RoleName"
+          :value="item.RoleId"
+        ></t-option>
+      </t-select>
+    </div>
+    <div class="bg-white main-wrap">
+      <div style="font-weight:600">ETACRM菜单权限</div>
+      <div class="list-wrap">
+        <t-checkbox-group v-model="item.CheckList" v-for="item in menuList" :key="item.MenuId" class="list-item">
+          <t-checkbox 
+            :key="item.MenuId" 
+            :check-all="true"
+            :checked="item.CheckList.length>0?true:false"
+            :indeterminate="item.CheckList.length>0&&item.CheckList.length<item.Child.length?true:false"
+            :label="item.Name"
+            class="check-all-box"
+          />
+            <t-checkbox 
+              :key="child.MenuId" 
+              :value="child.MenuId" 
+              v-for="child in item.Child"
+            >{{child.Name}}</t-checkbox>
+        </t-checkbox-group>
+      </div>
+    </div>
+    <div class="bg-white" style="text-align:center;padding-bottom:40px">
+      <t-button style="width:300px" @click="handleSave">确定</t-button>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.top-wrap {
+  padding: 20px;
+  align-items: center;
+  gap: 0 10px;
+}
+.main-wrap {
+  margin-top: 20px;
+  padding: 20px;
+  .list-wrap{
+    margin-top: 60px;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 30px;
+    .list-item{
+      width: 200px;
+      display: flex;
+      flex-direction: column;
+      min-height: 200px;
+      border: 1px solid var(--border-color);
+      border-radius: 4px;
+      padding: 20px;
+      margin-bottom: 50px;
+      .check-all-box{
+        margin-top: -50px;
+        margin-left: -20px;
+        margin-bottom: 20px;
+      }
+    }
+  }
+}
+</style>

+ 3 - 2
vite.config.js

@@ -92,8 +92,9 @@ export default defineConfig(({ mode }) => {
       port:8900,
       proxy:{
         '/v1': {
-          // target: 'http://8.136.199.33:8900/v1',
-          target: 'http://8.136.199.33:7777/adminapi/',
+          // target: 'http://192.168.20.10:8912/v1',
+          target: 'http://8.136.199.33:8900/v1',
+          // target: 'http://8.136.199.33:7777/adminapi/',
           changeOrigin: true,
           rewrite: (path) => path.replace(/^\/v1/, ''),
         }