소스 검색

Merge branch 'v2.0' of http://8.136.199.33:3000/eta_forum/eta_forum_admin_front into v2.0

chenlei 1 일 전
부모
커밋
089e011043

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

@@ -44,4 +44,9 @@ export default{
     return get('/chart_collect/stat/chart',{})
   },
 
+  // 用户行为统计详情
+  getUserActionStatisticInfo:params=>{
+    return get('/chart_collect/stat/user/detailList',params)
+  },
+
 }

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

@@ -1,6 +1,16 @@
 import {get,post} from '@/api/index'
 
 export default{
+	// 上传图片
+	uploadImg:params=>{
+		const formData=new FormData()
+		formData.append('file',params.file)
+		return post('/resource/image/upload',formData)
+	},
+	//登录(根据code)
+	loginWithCode:params=>{
+		return post('/login/auth_code_login',params)
+	},
 	//机构用户
 	companyUserList:()=>{
 		return get('/admin/business/admin',{})

+ 8 - 4
src/api/system/set.js

@@ -1,8 +1,12 @@
 import {get,post} from '@/api/index'
 
 export default{
-    //登录(根据code)
-    loginWithCode:params=>{
-        return post('/login/auth_code_login',params)
-    }
+  // 获取系统配置信息
+	getConfigData:()=>{
+		return get('/config/fetch',{})
+	},
+	// 修改系统配置信息
+	updateConfigData:params=>{
+		return post('/config/save',params)
+	},
 }

+ 2 - 2
src/views/AutoLogin.vue

@@ -1,5 +1,5 @@
 <script setup>
-import {apiSystemSet,apiSystemCommon} from '@/api/system'
+import {apiSystemCommon} from '@/api/system'
 import { useRoute, useRouter } from 'vue-router'
 
 const route=useRoute()
@@ -21,7 +21,7 @@ async function handleNavigation(){
 function init(){
     const code=route.query.code
     if(!code) return
-    apiSystemSet.loginWithCode({
+    apiSystemCommon.loginWithCode({
         AuthCode:code
     }).then(res=>{
         if(res.Ret===200){

+ 21 - 1
src/views/customer/user/Index.vue

@@ -56,6 +56,7 @@ const tablePagination = ref({
   total: 0,
   showPageSize:false
 })
+let SortParam='',SortType='';
 async function getUserList(){
   const res=await apiCustomerUser.userList({
     PageSize:tablePagination.pageSize,
@@ -63,7 +64,9 @@ async function getUserList(){
     PositionStatus:filterState.jobStatus===''?-1:filterState.jobStatus,
     Enabled:filterState.accountStatus===''?-1:filterState.accountStatus,
     Keyword:filterState.keyword,
-    BusinessCode:filterState.customer
+    EtaBusinessId:filterState.customer,
+    SortParam:SortParam,
+    SortType:SortType
   })
   if(res.Ret!==200) return
   const arr=res.Data.List||[]
@@ -71,12 +74,27 @@ async function getUserList(){
   tablePagination.value.total=res.Data.Paging.Totals
 }
 getUserList()
+function handlePageChange(e){
+  tablePagination.value.current=e.current
+  getUserList()
+}
 
 function handleRefreshList(){
   tablePagination.value.current=1
   tableData.value=[]
   getUserList()
 }
+// 排序 sort undefined  descending:true|false
+function handleSortChange(sort,options){
+  if(sort){
+    SortParam=sort.sortBy
+    SortType=sort.descending?'desc':'asc'
+  }else{
+    SortParam=''
+    SortType=''
+  }
+  handleRefreshList()
+}
 
 const editUserData=ref(null)
 
@@ -209,6 +227,8 @@ async function handleImportUser(e){
         :pagination="tablePagination"
         show-header
         resizable
+        @page-change="handlePageChange"
+        @sort-change="handleSortChange"
       >
         <template #Mobile="{ row }">
           <span>{{row.CountryCode}}-{{row.Mobile}}</span>

+ 39 - 20
src/views/customer/user/components/ActionStatisticForChart.vue

@@ -2,6 +2,7 @@
 import Highcharts from "highcharts";
 import HighchartsMore from "highcharts/highcharts-more";
 import HighchartszhCN from "@/hooks/chart/highcahrts-zh_CN";
+import {apiCustomerUser} from '@/api/customer'
 
 
 HighchartszhCN(Highcharts);
@@ -29,9 +30,14 @@ const chartDefaultOpts = {
         inside: false,
         crop: false,
         overflow: true,
-        x: 80,
+        x: 140,
+        useHTML:true,
+        backgroundColor: 'rgba(255, 255, 255, 0)',
         formatter: function (e) {
-          return this.point.options.isLabel;
+          return `<div style="font-size:14px">
+            <span style="margin-right:5px;display:inline-block;width:40px;text-align:right;color:#fff">${this.point.options.y}</span>
+            <span style="display:inline-block;width:133px">${this.point.options.isLabel}</span>
+          </div>`;
         },
       },
     },
@@ -44,33 +50,33 @@ const chartDefaultOpts = {
   },
 }
 
-function chartRender() {
+function chartRender(data) {
   let series = [
     {
       name: '累计收藏图表量',
-      data: [
-        {
-          y: 10,
-          isLabel: '2024-10-10'
-        },
-        {
-          y: 10,
-          isLabel: '2024-10-10'
-        },
-        {
-          y: 10,
-          isLabel: '2024-10-10'
-        }
-      ]
+      data: []
     }
   ]
+
   let xAxis = {
-    categories: ['图表1','图表2','图表3',],
+    categories: [],
     tickWidth: 1,
     lineColor:'#E4E4E4',
     tickColor:'#E4E4E4',
     tickPosition: "outside",
+    labels: {
+      formatter: function () {
+        // 限制文字长度为 12 个字符,超出部分显示省略号
+        return this.value.length > 12 ? this.value.substring(0, 12) + '...' : this.value;
+      },
+      style: {
+        whiteSpace: 'nowrap', // 确保文字不会换行
+        overflow: 'hidden',   // 超出隐藏
+        textOverflow: 'ellipsis', // 文本省略号样式
+      }
+    }
   };
+  
   let yAxis = {
     opposite: true,
     gridLineWidth: 1,
@@ -88,6 +94,13 @@ function chartRender() {
     },
     reversedStacks: false,
   };
+  data.forEach(item => {
+    series[0].data.push({
+      y:item.CollectNum,
+      isLabel:item.LastCollectTime
+    })
+    xAxis.categories.push(item.ChartName)
+  });
 
   const options={
     ...chartDefaultOpts,
@@ -99,8 +112,11 @@ function chartRender() {
   Highcharts.chart(`fav-chart-statistic`, options);
 }
 
-function getChartDetail() {
-  chartRender()
+async function getChartDetail() {
+  const res=await apiCustomerUser.getUserActionStatisticChartData()
+  if(res.Ret!==200) return
+  const data=res.Data.List||[]
+  chartRender(data)
 }
 
 onMounted(() => {
@@ -122,5 +138,8 @@ onMounted(() => {
   .wrap-label {
     text-align: center;
   }
+  .chart-render-box{
+    height: calc(100vh - 300px);
+  }
 }
 </style>

+ 58 - 6
src/views/customer/user/components/ActionStatisticForCustomer.vue

@@ -25,6 +25,27 @@ const timeType = [
 const timeTypeValue = ref('')
 const selectDate = ref([])
 const selectBusinessValue=ref([])
+// 获取选择的起止日期值
+function getStartAndEndDate(){
+  let StartDate=selectDate.value?.[0]||'',EndDate=selectDate.value?.[1]||'';
+  if(timeTypeValue.value==='今天'){
+    StartDate=moment().format('YYYY-MM-DD')
+    EndDate=moment().format('YYYY-MM-DD')
+  }else if(timeTypeValue.value==='过去3天'){
+    EndDate=moment().format('YYYY-MM-DD')
+    StartDate=moment().subtract(3,'days').format('YYYY-MM-DD')
+  }else if(timeTypeValue.value==='过去一周'){
+    EndDate=moment().format('YYYY-MM-DD')
+    StartDate=moment().subtract(7,'days').format('YYYY-MM-DD')
+  }else if(timeTypeValue.value==='过去一月'){
+    EndDate=moment().format('YYYY-MM-DD')
+    StartDate=moment().subtract(30,'days').format('YYYY-MM-DD')
+  }
+  return {
+    StartDate,
+    EndDate
+  }
+}
 
 const tableData = ref([])
 const columns = [
@@ -39,14 +60,17 @@ const tablePagination = ref({
   total: 0,
   showPageSize: false
 })
+let SortParam='',SortType='';
 async function getStatisticList(){
-  let StartDate='',EndDate='';
+  
   const res=await apiCustomerUser.getUserActionStatistic({
     CurrentIndex:tablePagination.value.current,
     PageSize:tablePagination.value.pageSize,
     EtaBusinessIds:selectBusinessValue.value.join(','),
-    StartDate:selectDate.value?.[0]||'',
-    EndDate:selectDate.value?.[1]||'',
+    StartDate:getStartAndEndDate().StartDate,
+    EndDate:getStartAndEndDate().EndDate,
+    SortParam:SortParam,
+    SortType:SortType
   })
   if(res.Ret!==200) return
   tableData.value=res.Data.List||[]
@@ -54,6 +78,22 @@ async function getStatisticList(){
 
 }
 getStatisticList()
+function handlePageChange(e){
+  tablePagination.value.current=e.current
+  getStatisticList()
+}
+// 排序 sort undefined  descending:true|false
+function handleSortChange(sort,options){
+  console.log(sort,options);
+  if(sort){
+    SortParam=sort.sortBy
+    SortType=sort.descending?'desc':'asc'
+  }else{
+    SortParam=''
+    SortType=''
+  }
+  refreshList()
+}
 
 function refreshList(){
   tablePagination.value.current=1
@@ -74,7 +114,13 @@ function handleSelectDate(){
 }
 
 const showFavChart=ref(false)
-
+const activeUser=ref(null)
+const filterDate=ref(null)
+function handleShowDetail(item){
+  activeUser.value=item
+  filterDate.value=getStartAndEndDate()
+  showFavChart.value=true
+}
 </script>
 
 <template>
@@ -106,14 +152,20 @@ const showFavChart=ref(false)
     :pagination="tablePagination"
     show-header
     resizable
+    @page-change="handlePageChange"
+    @sort-change="handleSortChange"
   >
     <template #CollectNum="{row}">
-      <t-button size="small" theme="primary" variant="text">{{row.CollectNum}}</t-button>
+      <t-button size="small" theme="primary" variant="text" @click="handleShowDetail(row)">{{row.CollectNum}}</t-button>
     </template>
   </t-table>
 
   <!-- 用户收藏图表 -->
-  <FavChartStatistic v-model:show="showFavChart"/>
+  <FavChartStatistic 
+    v-model:show="showFavChart" 
+    :data="activeUser"
+    :filterDate="filterDate"
+  />
 </template>
 
 <style lang="scss" scoped>

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

@@ -58,7 +58,7 @@ async function handleSave(){
     CountryCode:formData.telCode,
     Mobile:formData.tel,
     Position:formData.post,
-    BusinessCode:formData.customer,
+    EtaBusinessId:formData.customer,
     DepartmentName:formData.depart,
     PositionStatus:formData.jobStatus
   }
@@ -86,7 +86,7 @@ watch(
         formData.name=props.data.RealName
         formData.telCode=props.data.CountryCode
         formData.tel=props.data.Mobile
-        formData.customer=props.data.BusinessCode
+        formData.customer=props.data.EtaBusinessId
         formData.post=props.data.Position
         formData.depart=props.data.DepartmentName
         formData.jobStatus=props.data.PositionStatus

+ 54 - 7
src/views/customer/user/components/FavChartStatistic.vue

@@ -1,22 +1,69 @@
 <script setup>
 import {SearchIcon} from 'tdesign-icons-vue-next'
+import {apiCustomerUser} from '@/api/customer'
+import { watch } from 'vue'
 
 const show = defineModel('show', { type: Boolean, default: false })
 const props=defineProps({
   data:{
     type:[null,Object],
     default:null
+  },
+  filterDate:{
+    type:Object,
+    default:()=>{}
   }
 })
 
 const keyword=ref('')
+let finished=false
+let loading=false
+let page=1
+const pageSize=30
+const list=ref([])
+async function getChartList(){
+  loading=true
+  const res=await apiCustomerUser.getUserActionStatisticInfo({
+    Keyword:keyword.value,
+    PageSize:pageSize,
+    CurrentIndex:page,
+    UserId:props.data.UserId,
+    StartDate:props.filterDate.StartDate,
+    EndDate:props.filterDate.EndDate
+  })
+  loading=false
+  if(res.Ret!==200) return
+  const arr=res.Data.List||[]
+  list.value=[...list.value,...arr]
+  finished=res.Data.Paging.IsEnd
+}
 
 function handleScroll({scrollBottom}){
-  if(scrollBottom<50){
-
+  if(scrollBottom<50&&!finished){
+    page++
+    getChartList()
   }
 }
 
+function handleSearch(){
+  page=1
+  finished=false
+  list.value=[]
+  getChartList()
+}
+
+watch(
+  ()=>show.value,
+  (n)=>{
+    if(n){
+      page=1
+      finished=false
+      list.value=[]
+      getChartList()
+    }
+  }
+)
+
 </script>
 
 <template>
@@ -32,16 +79,16 @@ function handleScroll({scrollBottom}){
     :footer="false"
     class="fav-chart-wrap"
   >
-    <t-input placeholder="图表名称" v-model="keyword" clearable>
+    <t-input placeholder="图表名称" v-model="keyword" clearable @change="handleSearch">
       <template #prefixIcon><SearchIcon /></template>
     </t-input>
     <t-list class="chart-list" @scroll="handleScroll">
-      <div class="chart-item-box" v-for="item in 26" :key="item">
-        <div class="text-ellipsis--l1 title">图表标题图表标题图表标题图表标题</div>
-        <img class="img" src="" alt="">
+      <div class="chart-item-box" v-for="item in list" :key="item.ChartCollectId">
+        <div class="text-ellipsis--l1 title">{{item.ChartName}}</div>
+        <img class="img" :src="item.ChartImage" alt="">
         <div>
           <span>收藏时间:</span>
-          <span>{{formatTime('2024-10-10','YYYY-MM-DD')}}</span>
+          <span>{{formatTime(item.CollectTime,'YYYY-MM-DD')}}</span>
         </div>
       </div>
     </t-list>

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

@@ -25,7 +25,7 @@ async function handleSave(){
   if(validRes!==true) return
   const res=await apiCustomerUser.moveUser({
     UserId:props.data.UserId,
-    BusinessCode:formData.company
+    EtaBusinessId:formData.company
   })
   if(res.Ret!==200) return
   show.value=false
@@ -75,7 +75,7 @@ watch(
       
       <t-form-item label="所属客户" name="customer">
         <select-business 
-          :value="props.data?.BusinessCode"
+          :value="props.data?.EtaBusinessId"
           placeholder="输入社会信用码或客户名称"
           disabled
           v-if="show"

+ 42 - 1
src/views/system/CommonSet.vue

@@ -1,8 +1,48 @@
 <script setup>
+import {apiSystemCommon,apiSystemSet} from '@/api/system'
 
 const chartWaterImgs=ref([])
 async function handleUploadImg(e){
   const file=e.raw
+  const res=await apiSystemCommon.uploadImg({
+    file:file
+  })
+  const resObj={
+    status:'',
+    error:'',
+    response:{
+      url:''
+    }
+  }
+  if(res.Ret!==200){
+    resObj.status='fail'
+    resObj.error='上传失败'
+  }else{
+    resObj.status='success'
+    resObj.response.url=res.Data.ResourceUrl
+    chartWaterImgs.value=[{url:res.Data.ResourceUrl}]
+  }
+
+  return resObj
+}
+
+// 获取配置
+async function getConfigData(){
+  const res=await apiSystemSet.getConfigData()
+  if(res.Ret!==200) return
+  if(res.Data.CompanyWatermark){
+    chartWaterImgs.value=[{url:res.Data.CompanyWatermark}]
+  }
+}
+getConfigData()
+
+// 保存配置
+async function handleSaveConfig(){
+  const res=await apiSystemSet.updateConfigData({
+    CompanyWatermark:chartWaterImgs.value[0]?.url||''
+  })
+  if(res.Ret!==200) return
+  MessagePlugin.success('保存成功')
 }
 
 </script>
@@ -15,6 +55,7 @@ async function handleUploadImg(e){
       theme="image"
       tips="上传格式:png、jpg"
       accept="image/png,image/jpeg"
+      :showImageFileName="false"
       :request-method="handleUploadImg"
       :locale="{
         triggerUploadText: {
@@ -22,7 +63,7 @@ async function handleUploadImg(e){
         },
       }"
     />
-    <t-button style="margin-top:30px">应用到全部社区图表</t-button>
+    <t-button style="margin-top:30px" @click="handleSaveConfig">应用到全部社区图表</t-button>
   </div>
 </template>
 

+ 5 - 5
src/views/system/RoleMenuAuth.vue

@@ -63,11 +63,11 @@ async function handleSave(){
             :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 
+            :key="child.MenuId" 
+            :value="child.MenuId" 
+            v-for="child in item.Child"
+          >{{child.Name}}</t-checkbox>
         </t-checkbox-group>
       </div>
     </div>