Explorar el Código

江门2.2.0版本代码

tangning hace 1 semana
padre
commit
79881da84f

+ 4 - 0
src/App.vue

@@ -16,6 +16,9 @@
   import { useAppStoreWithOut } from '/@/store/modules/app';
   import { useMessage } from '/@/hooks/web/useMessage';
 
+  import zhCN from 'ant-design-vue/es/locale/zh_CN';
+  import dayjs from 'dayjs';
+  import 'dayjs/locale/zh-cn';
   // support Multi-language
   const { createConfirm } = useMessage();
   const { getAntdLocale } = useLocale();
@@ -27,6 +30,7 @@
     // localStorage.removeItem('token');
   }
   // Listening to page changes and dynamically changing site titles
+  dayjs.locale('zh-cn');
   useTitle();
 </script>
 

+ 22 - 0
src/api/jyUserPlatform/index.ts

@@ -18,6 +18,8 @@ enum Api {
   yhdel = '/service/manage/jyUserPlatform/del',
   addressKey = '/service/manage/index/addressKey/',
   sceneGroupCount = '/service/manage/scene/sceneGroupCount/',
+  getDistrict = '/service/manage/data/getDistrict',
+  getJyType = '/service/manage/data/getJyType',
 }
 
 /**
@@ -196,3 +198,23 @@ export const platformallList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
+export const getDistrict = (params) =>
+  defHttp.get({
+    url: Api.getDistrict,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const getJyType = (params) =>
+  defHttp.get({
+    url: Api.getJyType,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });

+ 110 - 28
src/api/statistics/index.ts

@@ -12,10 +12,17 @@ enum Api {
   orderTrend = '/service/manage/data/orderTrend',
   cameraTrend = '/service/manage/data/cameraTrend',
   sceneTrend = '/service/manage/data/sceneTrend',
-  sceneTotal = '/service/manage/data/sceneTotal',
+  sceneTotal = '/service/manage/data/sceneTotal2',
   cameraExport = '/service/manage/order/camera/export',
   downExport = '/service/manage/order/down/export',
   incrementExport = '/service/manage/order/increment/export',
+  jyScatter = '/service/manage/data/jyScatter',
+  districtScatter = '/service/manage/data/districtScatter',
+  exportSceneList = '/service/manage/data/exportSceneList',
+  pageDataAuth = '/service/manage/data/pageAuthAdd',
+  pageAuthList = '/service/manage/data/pageAuthList',
+  delPageAuth = '/service/manage/data/delPageAuth',
+  platformList = '/service/manage/data/platformList',
 }
 
 /**
@@ -32,8 +39,49 @@ export const buryPointList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
+export const platformList = (params: PageParams) =>
+  defHttp.get<Result>({
+    url: Api.platformList,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
 
-  export const buryPointAdd = (params: PageParams) =>
+export const delPageAuth = (params) =>
+  defHttp.post<Result>({
+    url: Api.delPageAuth,
+    params,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const pageAuthList = (params) =>
+  defHttp.post<Result>({
+    url: Api.pageAuthList,
+    params,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const pageDataAuth = (params) =>
+  defHttp.post<Result>({
+    url: Api.pageDataAuth,
+    params,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const buryPointAdd = (params: PageParams) =>
   defHttp.post<Result>({
     url: Api.buryPointAdd,
     params,
@@ -43,7 +91,7 @@ export const buryPointList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
-  export const buryPointDlt = (params: PageParams) =>
+export const buryPointDlt = (params: PageParams) =>
   defHttp.post<Result>({
     url: Api.buryPointDlt,
     params,
@@ -53,7 +101,7 @@ export const buryPointList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
-  export const userTotal = () =>
+export const userTotal = () =>
   defHttp.get<Result>({
     url: Api.userTotal,
     headers: {
@@ -61,7 +109,7 @@ export const buryPointList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
-  export const userTrend = (params) =>
+export const userTrend = (params) =>
   defHttp.get<Result>({
     url: Api.userTrend,
     params,
@@ -71,7 +119,7 @@ export const buryPointList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
-  export const orderTotal = () =>
+export const orderTotal = () =>
   defHttp.get<Result>({
     url: Api.orderTotal,
     headers: {
@@ -79,8 +127,8 @@ export const buryPointList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
-  
-  export const orderTrend = (params) =>
+
+export const orderTrend = (params) =>
   defHttp.get<Result>({
     url: Api.orderTrend,
     params,
@@ -90,8 +138,8 @@ export const buryPointList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
-  
-  export const cameraTrend = (params) =>
+
+export const cameraTrend = (params) =>
   defHttp.get<Result>({
     url: Api.cameraTrend,
     params,
@@ -101,63 +149,97 @@ export const buryPointList = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
-  
-  export const sceneTotal = () =>
-  defHttp.get<Result>({
+
+export const sceneTotal = (params) =>
+  defHttp.post<Result>({
     url: Api.sceneTotal,
     headers: {
       // @ts-ignore
       ignoreCancelToken: true,
     },
+    params,
+    data: params,
   });
-  
-  export const sceneTrend = (params) =>
-  defHttp.get<Result>({
-    url: Api.sceneTrend,
+
+export const jyScatter = (params) =>
+  defHttp.post<Result>({
+    url: Api.jyScatter,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
     params,
     data: params,
+  });
+export const districtScatter = (params) =>
+  defHttp.post<Result>({
+    url: Api.districtScatter,
     headers: {
       // @ts-ignore
       ignoreCancelToken: true,
     },
+    params,
+    data: params,
   });
-  
-    
-  export const cameraExport = (params) =>
+
+export const sceneTrend = (params) =>
+  defHttp.post<Result>({
+    url: Api.sceneTrend,
+    params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const cameraExport = (params) =>
   defHttp.downloadFile<FileStream>({
     url: Api.cameraExport,
     params: params,
     // data: params,
-    fileName:'相机订单.xlsx',
+    fileName: '相机订单.xlsx',
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+    responseType: 'blob',
+  });
+export const exportSceneList = (params) =>
+  defHttp.downloadFile<FileStream>({
+    url: Api.exportSceneList,
+    params: params,
+    method: 'post',
+    // data: params,
+    fileName: '场景.xlsx',
     headers: {
       // @ts-ignore
       ignoreCancelToken: true,
     },
-    responseType: 'blob'
+    responseType: 'blob',
   });
 
-  export const downExport = (params) =>
+export const downExport = (params) =>
   defHttp.downloadFile<FileStream>({
     url: Api.downExport,
     params: params,
     // data: params,
-    fileName:'下载订单.xlsx',
+    fileName: '下载订单.xlsx',
     headers: {
       // @ts-ignore
       ignoreCancelToken: true,
     },
-    responseType: 'blob'
+    responseType: 'blob',
   });
 
-  export const incrementExport = (params) =>
+export const incrementExport = (params) =>
   defHttp.downloadFile<FileStream>({
     url: Api.incrementExport,
     params: params,
-    fileName:'权益订单.xlsx',
+    fileName: '权益订单.xlsx',
     // data: params,
     headers: {
       // @ts-ignore
       ignoreCancelToken: true,
     },
-    responseType: 'blob'
+    responseType: 'blob',
   });

+ 38 - 10
src/utils/treeUtils.ts

@@ -55,18 +55,18 @@ export function getTreeId(treeNodes: TreeMenuNode[]): number[] {
   // 如果明确节点是顺序可以保证先父后子,可以省去这次遍历,在后面边遍历过程中填充查找表
   // const nodesMap = new Map<number, TreeNode>(treeNodes.map((node) => [node.id, node]));
   // 引入虚拟根节点来统一实现 parent 始终有效,避免空判断
-  let TreeIdList:number[] =  []
-  function getTreeIdList(list:TreeMenuNode[]) {
-    return list.map(ele => {
-      if(ele.children && ele.children.length){
-        getTreeIdList(ele.children)
-      }else{
-        TreeIdList.push(ele.id)
+  const TreeIdList: number[] = [];
+  function getTreeIdList(list: TreeMenuNode[]) {
+    return list.map((ele) => {
+      if (ele.children && ele.children.length) {
+        getTreeIdList(ele.children);
+      } else {
+        TreeIdList.push(ele.id);
       }
-    })
+    });
   }
-  getTreeIdList(treeNodes)
-  console.log('TreeIdList',TreeIdList,treeNodes)
+  getTreeIdList(treeNodes);
+  console.log('TreeIdList', TreeIdList, treeNodes);
   return TreeIdList ?? [];
 }
 
@@ -81,3 +81,31 @@ export function makeMenuTree(treeNodes: TreeMenuNode[]): TreeMenuNode[] {
   });
   return virtualRoot.children ?? [];
 }
+/**
+ * 递归修改文件树的字段名称
+ * @param {Array|Object} tree - 文件树数据(数组/单个节点对象)
+ * @param {Object} fieldMap - 字段名映射表 { 原字段名: 目标字段名 }
+ * @returns {Array|Object} 修改后的文件树
+ */
+export function renameTreeFields(tree, fieldMap) {
+  // 边界条件:空值直接返回
+  if (tree === null || typeof tree !== 'object') {
+    return tree;
+  }
+
+  // 如果是数组,递归处理每个元素
+  if (Array.isArray(tree)) {
+    return tree.map((item) => renameTreeFields(item, fieldMap));
+  }
+
+  // 如果是对象,遍历所有键并替换
+  const newNode = {
+    ...tree,
+    label: tree.nameSn,
+    value: tree.code,
+    // 替换字段名(如果在映射表中)
+    [fieldMap['childrenList']]: renameTreeFields(tree.childrenList, fieldMap),
+    // [fieldMap['children']]: renameTreeFields(tree.children, fieldMap),
+  };
+  return newNode;
+}

+ 52 - 22
src/views/lanUser/detailsModal.vue

@@ -7,7 +7,7 @@
     :min-height="150"
     @ok="handleOk"
   >
-    <BasicForm @register="registerForm" >
+    <BasicForm @register="registerForm">
       <template #selectUser="{ model, field }">
         <Select
           v-model:value="model[field]"
@@ -23,7 +23,7 @@
           @change="handleChange"
         />
       </template>
-      </BasicForm>
+    </BasicForm>
   </BasicModal>
 </template>
 <script lang="ts">
@@ -50,6 +50,12 @@
       const userStore = useUserStore();
       const userinfo = computed(() => userStore.getUserInfo);
       const options = ref([]);
+      const active = ref({
+        phone: null,
+        id: null,
+        name: null,
+        idCard: null,
+      });
       const preventAutoFill = ref(true);
       const { companyId } = userinfo.value;
       console.log('companyId', companyId);
@@ -62,8 +68,7 @@
         const fetchId = lastFetchId;
         options.value = [];
         queryByKey({ queryKey: value }).then((res) => {
-          console.log('queryByKey', res);
-          setFieldsValue({idkey: null,});
+          setFieldsValue({ idkey: null });
           const data = res.map((user) => ({
             ...user,
             label: `${user.name}/${user.phone || '暂无手机号码'}/${user.idCard || '暂无身份证'}/${
@@ -72,6 +77,7 @@
             value: user.id,
           }));
           options.value = data;
+          console.log('queryByKey', res, data);
         });
       }, 300);
       const schemas: FormSchema[] = [
@@ -121,16 +127,11 @@
             onChange: (e) => {
               let addType = e.target.value;
               console.log('data', addType);
-              updateSchema([{
-                  field: 'name',
-                  ifShow: addType !== 'old',
-                },{
-                  field: 'idCard',
-                  ifShow: addType !== 'old',
-                },{
-                  field: 'idkey',
-                  ifShow: addType == 'old',
-                }])
+              active.value = {};
+              showItem(addType);
+              setFieldsValue({
+                idkey: null,
+              });
             },
           },
         },
@@ -221,18 +222,26 @@
       function onDataReceive(data) {
         // 方式1;
         title.value = data.status == 1 ? '启用平台' : data.id ? '修改平台' : '创建平台';
+        showItem('new');
         // preventAutoFill.value = false
         setTimeout(() => {
           console.log('useModalInner', data);
           setFieldsValue({
             ...data,
+            addType: 'new',
             userName: '',
             password: '',
             roleId: data.roleId != 2 ? data.roleId : '',
           });
         }, 200);
       }
+      /**
+       * 处理选择框值变更
+       * @param value 选中的值
+       * @param b 选中的完整对象项
+       */
       function handleChange(value, b) {
+        console.log('handleChange', value, b);
         active.value = b;
       }
       function companyIdChange(companyId) {
@@ -253,14 +262,18 @@
       }
       async function handleOk() {
         let data = await validate();
-        let res = await addOrUpdate({
-          ...data,
-          // userName: data.phone,
-          phone: data.phone,
-          nickName: data.nickName,
-          roleId: data.roleId,
-          id: data.id,
-        });
+        let newdata = active.value;
+        let apiData = data;
+        if (data.addType != 'new') {
+          apiData = {
+            ...data,
+            // id: active.value.id,
+            phone: active.value.phone,
+            name: active.value.name,
+            idCard: active.value.idCard,
+          };
+        }
+        let res = await addOrUpdate(apiData);
         console.log('res', res);
         context && context.emit('ok', res);
         let url = window.location.origin + window.location.pathname + '?key=' + res.platformAddress;
@@ -361,11 +374,28 @@
         }
         return true;
       };
+      function showItem (addType) {
+        updateSchema([
+          {
+            field: 'name',
+            ifShow: addType !== 'old',
+          },
+          {
+            field: 'idCard',
+            ifShow: addType !== 'old',
+          },
+          {
+            field: 'idkey',
+            ifShow: addType == 'old',
+          },
+        ]);
+      }
       return {
         register,
         title,
         preventAutoFill,
         schemas,
+        options,
         registerForm,
         modelRef,
         handleOk,

+ 2 - 1
src/views/productOperation/modal/uploadModal.vue

@@ -8,6 +8,7 @@
     @cancel="resetFields"
     @ok="handleSubmit"
     :loading="loading"
+    :okText="loading?`${fileFlow.complete}%`:'确定'"
     :confirmLoading="loading"
     :min-height="0"
   >
@@ -33,7 +34,7 @@
           </Upload>
         </template>
       </BasicForm>
-      <!-- :headers="headers" <span>注意:迁移后该场景的权限配置将被清空,如需保留,请复制后再做迁移</span> -->
+      <div v-if="fileFlow.list.length == 0" style="padding-left: 83px">注‌支持采集完成后,导出的场景原始数据上传。</div>
     </div>
   </BasicModal>
 </template>

+ 110 - 61
src/views/statistics/components/VisitSource.vue

@@ -2,31 +2,51 @@
   <Card title="访问来源" :loading="loading">
     <template #extra>
       <div class="condition">
-        <div class="selct" style="display: inline-block">
+        <div class="selct" style="display: inline-block" v-if="district.length">
           <!-- <span style="margin-right:15px"></span> -->
-          <Select
-            v-model:value="type"
+          <!-- <Select
+            v-model:value="SearchData.districtCode"
             style="width: 100px; margin-right: 8px"
             placeholder="全部地区"
-            :options="typeOptions"
+            allowClear
+            :options="district"
+            @change="handleType"
+          /> -->
+          <ApiTreeSelect
+            v-model:value="SearchData.districtCode"
+            style="width: 100px; margin-right: 8px"
+            :dropdown-match-select-width="false"
+            :dropdown-style="{ maxHeight: '400px', overflow: 'auto', minWidth: '300px' }"
+            placeholder="全部地区"
+            show-search
+            tree-node-filter-prop="label"
+            :getPopupContainer="trigger => trigger.parentNode"
+            allowClear
+            :treeData="district"
             @change="handleType"
           />
         </div>
         <div class="selct" style="display: inline-block; margin-right: 0px">
-          <RangePicker v-model:value="selectTime" :picker="picker" />
+          <RangePicker @change="handleType" valueFormat="YYYY-MM-DD" :getCalendarContainer="trigger => trigger.parentNode" v-model:value="SearchData.timeList" :picker="picker" />
         </div>
       </div>
     </template>
-    <div ref="chartRef" :style="{ width, height }"></div>
+    <div ref="chartRef" v-show="echartData.length" :style="{ width, height }"></div>
+    <div class="noData" v-show="!echartData.length">暂无数据</div>
   </Card>
 </template>
 <script lang="ts" setup>
-  import { Ref, ref, watch } from 'vue';
+  import { Ref, ref, watch, onMounted } from 'vue';
+  import { basicProps } from './props';
   import { Card, Select, DatePicker } from 'ant-design-vue';
+  import { jyScatter } from '/@/api/statistics/index';
+  // import { district } from '/@/views/statistics/scene/data';
+  import ApiTreeSelect from '/@/components/Form/src/components/ApiTreeSelect.vue';
   const { RangePicker } = DatePicker;
   import { useECharts } from '/@/hooks/web/useECharts';
   const props = defineProps({
     loading: Boolean,
+    ...basicProps,
     width: {
       type: String as PropType<string>,
       default: '100%',
@@ -36,6 +56,22 @@
       default: '300px',
     },
   });
+  const district = ref(props.district);
+  // const jyType = ref(props.jyType);
+  const SearchData = ref({
+    timeList: [],
+    jyType: null,
+    districtCode: null,
+    cameraType: props.cameraType,
+    platformId: props.platformId,
+    type: 2,
+  });
+  const echartData = ref([
+    { value: 1048, name: '搜索引擎' },
+    { value: 735, name: '直接访问' },
+    { value: 580, name: '邮件营销' },
+    { value: 484, name: '联盟广告' },
+  ]);
   const options = ref([
     {
       value: 'jack',
@@ -49,65 +85,78 @@
   var colorList = ['#73DDFF', '#73ACFF', '#FDD56A', '#FDB36A', '#FD866A', '#9E87FF', '#58D5FF'];
   const chartRef = ref<HTMLDivElement | null>(null);
   const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
-  watch(
-    () => props.loading,
-    () => {
-      if (props.loading) {
-        return;
-      }
-      setOptions({
-        tooltip: {
-          trigger: 'item',
-        },
-        legend: {
-          bottom: '1%',
-          show: false,
-          left: 'center',
-        },
-        series: [
-          {
-            type: 'pie',
-            center: ['50%', '50%'],
-            radius: ['40%', '60%'],
-            clockwise: true,
-            avoidLabelOverlap: true,
-            hoverOffset: 15,
-            itemStyle: {
-              normal: {
-                color: function (params) {
-                  return colorList[params.dataIndex];
-                },
+  function handleType() {
+    getList();
+  }
+  async function getList() {
+    const list = await jyScatter(SearchData.value);
+    echartData.value = list || [];
+    setOptions({
+      tooltip: {
+        trigger: 'item',
+      },
+      legend: {
+        bottom: '1%',
+        show: false,
+        left: 'center',
+      },
+      series: [
+        {
+          type: 'pie',
+          center: ['50%', '50%'],
+          radius: ['40%', '60%'],
+          clockwise: true,
+          avoidLabelOverlap: true,
+          hoverOffset: 15,
+          itemStyle: {
+            normal: {
+              color: function (params) {
+                return colorList[params.dataIndex];
               },
             },
-            label: {
-              show: true,
-              position: 'outside',
-              formatter: '{a|{b}:{d}%}\n{hr|}',
-              rich: {
-                a: {
-                  padding: [-30, 15, -20, 15],
-                },
+          },
+          label: {
+            show: true,
+            position: 'outside',
+            formatter: '{a|{b}:{d}%}\n{hr|}',
+            rich: {
+              a: {
+                padding: [-30, 15, -20, 15],
               },
             },
-            labelLine: {
-              normal: {
-                length: 20,
-                length2: 10,
-                lineStyle: {
-                  width: 1,
-                },
+          },
+          labelLine: {
+            normal: {
+              length: 20,
+              length2: 10,
+              lineStyle: {
+                width: 1,
               },
             },
-            data: [
-              { value: 1048, name: '搜索引擎' },
-              { value: 735, name: '直接访问' },
-              { value: 580, name: '邮件营销' },
-              { value: 484, name: '联盟广告' },
-            ],
           },
-        ],
-      });
-    },
-    { immediate: true },
-  );
+          data: echartData.value,
+        },
+      ],
+    });
+    console.log(list, 'jyScatter');
+  }
+  onMounted(() => {
+    getList();
+  });
+  // watch(
+  //   () => props.loading,
+  //   () => {
+  //     if (props.loading) {
+  //       return;
+  //     };
+  //   },
+  //   { immediate: true },
+  // );
 </script>
+<style lang="less" scoped>
+.noData{
+  text-align: center;
+  line-height: 280px;
+  color: #999;
+}
+</style>

+ 118 - 96
src/views/statistics/components/lineEcharts2.vue

@@ -1,30 +1,41 @@
 <template>
   <Card title="采集趋势" :loading="loading">
-    <template #extra>
+    <template #extra v-if="!hiddens">
       <div class="condition">
         <div class="selct" style="display: inline-block">
           <!-- <span style="margin-right:15px"></span> -->
-          <Select
-            v-model:value="type"
+          <ApiTreeSelect
+            v-model:value="SearchData.districtCode"
             style="width: 100px; margin-right: 8px"
+            :dropdown-match-select-width="false"
+            :dropdown-style="{ maxHeight: '400px', overflow: 'auto', minWidth: '300px' }"
             placeholder="全部地区"
-            :options="typeOptions"
+            show-search
+            tree-node-filter-prop="label"
+            :getPopupContainer="(trigger) => trigger.parentNode"
+            allowClear
+            :treeData="district"
             @change="handleType"
           />
         </div>
-
-        <div class="selct" style="display: inline-block">
-          <!-- <span style="margin-right:15px">颗粒度</span> -->
+        <div class="selct" style="display: inline-block" v-if="jyType.length">
           <Select
-            v-model:value="value"
+            v-model:value="SearchData.jyType"
             style="width: 100px; margin-right: 8px"
             placeholder="全部警种"
-            :options="options"
+            allowClear
+            :options="jyType"
             @change="handleData"
           />
         </div>
         <div class="selct" style="display: inline-block; margin-right: 0px">
-          <RangePicker v-model:value="selectTime" :picker="picker" />
+          <RangePicker
+            @change="handleTime"
+            valueFormat="YYYY-MM-DD"
+            :getCalendarContainer="(trigger) => trigger.parentNode"
+            v-model:value="SearchData.timeList"
+            :picker="picker"
+          />
         </div>
       </div>
     </template>
@@ -36,46 +47,33 @@
   // import { dateUtil } from '/@/utils/dateUtil';
 </script>
 <script lang="ts" setup>
+  import { sceneTrend } from '/@/api/statistics/index';
   import { Card, Select, DatePicker } from 'ant-design-vue';
   const { RangePicker } = DatePicker;
-  import { ref, Ref, watch } from 'vue';
-  // import type { dataItemType } from './props';
+  import ApiTreeSelect from '/@/components/Form/src/components/ApiTreeSelect.vue';
+  import { ref, Ref, onMounted } from 'vue';
+  // import { district, jyType } from '/@/views/statistics/scene/data';
   import { useECharts } from '/@/hooks/web/useECharts';
   import type { Dayjs } from 'dayjs';
   const props = defineProps({
     loading: Boolean,
+    hiddens: Boolean,
     ...basicProps,
   });
-
+  console.log('district', props);
+  const district = ref(props.district);
+  const jyType = ref(props.jyType);
+  const hiddens = ref(props.hiddens || false);
   type RangeValue = [Dayjs, Dayjs];
   const picker = ref('date');
-  const value = ref(null);
-  const selectTime = ref<RangeValue>();
-  const options = ref<SelectProps['options']>([
-    {
-      value: '1',
-      label: '日',
-    },
-    {
-      value: '2',
-      label: '周',
-    },
-    {
-      value: '2',
-      label: '月',
-    },
-  ]);
-  const type = ref(null);
-  const typeOptions = ref<SelectProps['options']>([
-    {
-      value: '1',
-      label: '数量',
-    },
-    {
-      value: '2',
-      label: '金额',
-    },
-  ]);
+  const SearchData = ref({
+    timeList: [],
+    jyType: null,
+    platformId: props.platformId,
+    cameraType: props.cameraType,
+    districtCode: null,
+    type: 2,
+  });
   const viewStaticsData = ref<number[]>([1, 5, 6, 8, 55, 1, 5, 6, 8, 1]);
   const shareStaticsData = ref<number[]>([2, 55, 10, 2, 6, 1, 5, 6, 8, 1]);
   const yixStringData = ref<string[]>(['11', '22', '33', '44', 'ss', '11', '22', '33', '44', 'ss']);
@@ -83,17 +81,40 @@
   const chartRef = ref<HTMLDivElement | null>(null);
   const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
   function handleData(val) {
-    let obj = {
-      1: 'date',
-      2: 'week',
-      3: 'month',
-    };
-    console.log('handleChange', val);
+    console.log('handleData', val, SearchData.value.jyType);
+    // SearchData.value.jyType = val;
+    getList();
   }
+  function handleTime(val) {
+    console.log('handleChange', val, SearchData.value.timeList);
+    // SearchData.value.districtCode = val;
+    getList();
+  }
+
   function handleType(val) {
     console.log('handleChange', val);
+    // SearchData.value.districtCode = val;
+    getList();
   }
   function handlesetOptions() {
+    let series = [
+      {
+        data: shareStaticsData.value,
+        type: 'line',
+        itemStyle: { color: '#4cca73' },
+        // barMaxWidth: 80,
+        name: '采集场景',
+      },
+    ];
+    if (!hiddens.value) {
+      series.unshift({
+        data: viewStaticsData.value,
+        type: 'line',
+        itemStyle: { color: '#38a0ff' },
+        // barMaxWidth: 80,
+        name: '采集人数',
+      });
+    }
     setOptions({
       tooltip: {
         trigger: 'axis',
@@ -108,10 +129,8 @@
         orient: 'horizontal',
         bottom: 0,
       },
-      // grid: { left: '2%', right: '2%', top: '10%', bottom: '10%', containLabel: true },
       xAxis: {
         type: 'category',
-        // data: [...new Array(30)].map((_item, index) => `${index + 1}日`),
         data: yixStringData.value,
       },
       yAxis: {
@@ -119,54 +138,57 @@
         max: maxSize.value,
         splitNumber: 4,
       },
-      series: [
-        {
-          data: viewStaticsData.value,
-          type: 'line',
-          itemStyle: { color: '#38a0ff' },
-          // barMaxWidth: 80,
-          name: '用户浏览量',
-        },
-        {
-          data: shareStaticsData.value,
-          type: 'line',
-          itemStyle: { color: '#4cca73' },
-          // barMaxWidth: 80,
-          name: '用户分享数',
-        },
-      ],
+      series: series,
+      // [
+      //   {
+      //     data: viewStaticsData.value,
+      //     type: 'line',
+      //     itemStyle: { color: '#38a0ff' },
+      //     // barMaxWidth: 80,
+      //     name: '采集人数',
+      //   },
+      //   {
+      //     data: shareStaticsData.value,
+      //     type: 'line',
+      //     itemStyle: { color: '#4cca73' },
+      //     // barMaxWidth: 80,
+      //     name: '采集场景',
+      //   },
+      // ],
     });
   }
-  // props.viewStatics,
-  watch(
-    // () => [props.viewStatics, props.shareStatics],
-    // ([data1, data2]) => {
-    () => props.loading,
-    () => {
-      console.log('viewStatics-data');
-      // viewStaticsData.value = data1.reduce<number[]>(
-      //   (prev: number[], current) => prev.concat(Number(current.amount)),
-      //   [],
-      // );
-
-      // yixStringData.value = data1.reduce<string[]>(
-      //   (prev: string[], current) => prev.concat(current.date),
-      //   [],
-      // );
-      // shareStaticsData.value = data2.reduce<number[]>(
-      //   (prev: number[], current) => prev.concat(Number(current.amount)),
-      //   [],
-      // );
-
-      const maxNumber = Math.max(...viewStaticsData.value.concat(shareStaticsData.value));
-      const pow = Math.pow(10, maxNumber.toString().length - 1);
-      maxSize.value = maxNumber > 10 ? Math.floor(maxNumber / 10) * 10 + pow * 2 : 10;
-      console.log('maxSize', maxSize.value);
-      handlesetOptions();
-    },
-    {
-      immediate: true,
-      deep: true,
-    },
-  );
+  async function getList() {
+    const xData = [],
+      data1 = [],
+      data2 = [];
+    const list = await sceneTrend(SearchData.value);
+    console.log('sceneTrend', list, hiddens.value);
+    // const list1 = list.find((ele) => ele.type == 'scene') || { list: [] };
+    // const list2 = list.find((ele) => ele.type == 'user') || { list: [] };
+    list.map((ele) => {
+      xData.push(ele.groupKey);
+      data1.push(ele.sceneCount || 0);
+      data2.push(ele.userCount || 0);
+    });
+    // list2.list.map((ele) => {
+    //   data2.push(ele.totalCount || 0);
+    // });
+    shareStaticsData.value = data1;
+    viewStaticsData.value = data2;
+    yixStringData.value = xData;
+    const maxNumber = Math.max(...viewStaticsData.value.concat(shareStaticsData.value));
+    const pow = Math.pow(10, maxNumber.toString().length - 1);
+    maxSize.value = maxNumber > 10 ? Math.floor(maxNumber / 10) * 10 + pow * 2 : 10;
+    console.log(
+      'maxSize',
+      maxSize.value,
+      viewStaticsData.value,
+      shareStaticsData.value,
+      yixStringData.value,
+    );
+    handlesetOptions();
+  }
+  onMounted(() => {
+    getList();
+  });
 </script>

+ 67 - 60
src/views/statistics/components/orderEchart.vue

@@ -1,13 +1,46 @@
 <template>
   <Card :title="title || '订单数据统计'">
     <template #extra>
-      <condition
-        type="2"
-        :typeShow="title == '相机出库数量统计'"
-        :name="title == '订单数据统计' ? { 1: '金额', 0: '数量' } : {}"
-        @change="Search"
-        @expor="expor"
-      />
+      <div class="condition">
+        <div class="selct" style="display: inline-block">
+          <!-- <span style="margin-right:15px"></span> -->
+          <!-- <Select
+            v-model:value="SearchData.districtCode"
+            style="width: 100px; margin-right: 8px"
+            placeholder="全部地区"
+            allowClear
+            :options="district"
+            @change="handleType"
+          /> -->
+          <ApiTreeSelect
+            v-model:value="SearchData.districtCode"
+            style="width: 100px; margin-right: 8px"
+            :dropdown-match-select-width="false"
+            :dropdown-style="{ maxHeight: '400px', overflow: 'auto', minWidth: '300px' }"
+            placeholder="全部地区"
+            show-search
+            tree-node-filter-prop="label"
+            :getPopupContainer="trigger => trigger.parentNode"
+            allowClear
+            :treeData="district"
+            @change="handleType"
+          />
+        </div>
+        <div class="selct" style="display: inline-block" v-if="jyType.length">
+          <!-- <span style="margin-right:15px">颗粒度</span> -->
+          <Select
+            v-model:value="SearchData.jyType"
+            style="width: 100px; margin-right: 8px"
+            placeholder="全部警种"
+            allowClear
+            :options="jyType"
+            @change="handleType"
+          />
+        </div>
+        <div class="selct" style="display: inline-block; margin-right: 0px">
+          <RangePicker @change="handleType" valueFormat="YYYY-MM-DD" :getCalendarContainer="trigger => trigger.parentNode" v-model:value="SearchData.timeList" :picker="picker" />
+        </div>
+      </div>
     </template>
     <div ref="chartRef" :style="{ height, width }"></div>
   </Card>
@@ -15,52 +48,47 @@
 <script lang="ts" setup>
   import { basicProps } from './props';
   import condition from './condition.vue';
-  import { Card, DatePicker } from 'ant-design-vue';
+  import { Card, Select, DatePicker } from 'ant-design-vue';
+  import { districtScatter } from '/@/api/statistics/index';
+  import ApiTreeSelect from '/@/components/Form/src/components/ApiTreeSelect.vue';
+  const { RangePicker } = DatePicker;
   import { ref, Ref, watch, defineEmits, onMounted } from 'vue';
+  // import { district, jyType } from '/@/views/statistics/scene/data';
   import { useECharts } from '/@/hooks/web/useECharts';
   import { exportElsxFile } from '/@/utils/file/download';
   const props = defineProps({
     loading: Boolean,
     ...basicProps,
   });
+  const district = ref(props.district);
+  const jyType = ref(props.jyType);
   const emit = defineEmits(['alertSome']);
   const downOrderData = ref<number[]>([200, 100, 150, 200]);
-  const incrementOrderData = ref<number[]>([]);
-  const partsOrderData = ref<number[]>([]);
-  const yixStringData = ref<string[]>(['香洲区', '高新区', '斗门区', '金湾区']);
-  const echartTypr = ref('line');
-  const nameList = ref<string[]>(['下载订单', '权益订单', '配件订单']);
-  const maxSize = ref(0);
+  const yixStringData = ref<string[]>([]);
   const chartRef = ref<HTMLDivElement | null>(null);
   const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
-
-  function Search(val) {
-    emit('change', val);
+  const SearchData = ref({
+    timeList: [],
+    jyType: null,
+    districtCode: null,
+    cameraType: props.cameraType,
+    platformId: props.platformId,
+    type: 2,
+  });
+  function handleType() {
+    handlesetOptions();
   }
-  function expor(val) {
-    // emit('expor',val)
-    console.log('数量', val.value);
-    let hader = ['时间', ...nameList.value];
-    let fields = {
-      time: '日期',
-      '1': hader[1],
-      '2': hader[2],
-      '3': hader[3],
-    };
-    if (props.title == '订单数据统计' && val?.value) {
-      fields.time = `${val.value == 0 ? '数量/' : '金额/'}` + fields.time;
-    }
-    let data = yixStringData.value.map((ele, index) => {
+  async function handlesetOptions() {
+    let list = await districtScatter(SearchData.value);
+    yixStringData.value = list?.map((item) => item.groupName);
+    downOrderData.value = list?.map((item) => {
       return {
-        time: ele,
-        '1': (downOrderData.value && downOrderData.value[index]) || 0,
-        '2': (incrementOrderData.value && incrementOrderData.value[index]) || 0,
-        '3': (partsOrderData.value && partsOrderData.value[index]) || 0,
+        ...item,
+        value: item.totalCount,
+        name: item.groupName,
       };
     });
-    exportElsxFile(data, fields, props.title);
-  }
-  function handlesetOptions() {
+    console.log(list, 'districtScatter', downOrderData.value);
     setOptions({
       tooltip: {
         trigger: 'axis',
@@ -76,7 +104,6 @@
         show: false,
         bottom: 0,
       },
-      // grid: { left: '2%', right: '2%', top: '10%', bottom: '10%', containLabel: true },
       xAxis: {
         type: 'category',
         // data: [...new Array(30)].map((_item, index) => `${index + 1}日`),
@@ -92,31 +119,11 @@
         type: 'bar',
         itemStyle: { color: '#38a0ff' },
         barMaxWidth: 80,
-        name: 'nameList.value',
+        name: '地区分布',
       },
     });
   }
   onMounted(() => {
     handlesetOptions();
   })
-  // watch(
-  //   () => props.echartData,
-  //   (echartData) => {
-  //     downOrderData.value = echartData.downOrder || [];
-  //     incrementOrderData.value = echartData.incrementOrder || [];
-  //     partsOrderData.value = echartData.partOrder || [];
-  //     yixStringData.value = echartData.xdata || [];
-  //     if (echartData.nameList) {
-  //       nameList.value = echartData.nameList;
-  //     }
-  //     if (echartData.echartTypr) {
-  //       echartTypr.value = echartData.echartTypr;
-  //     }
-  //     handlesetOptions();
-  //   },
-  //   {
-  //     immediate: true,
-  //     deep: true,
-  //   },
-  // );
 </script>

+ 16 - 0
src/views/statistics/components/props.ts

@@ -54,4 +54,20 @@ export const basicProps = {
     type: String,
     default: '',
   },
+  platformId: {
+    type: String,
+    default: '',
+  },
+  cameraType: {
+    type: String,
+    default: '',
+  },
+  district: {
+    type: Array as PropType<any>,
+    default: [],
+  },
+  jyType: {
+    type: Array as PropType<any>,
+    default: [],
+  },
 };

+ 110 - 43
src/views/statistics/scene/addModal.vue

@@ -12,6 +12,20 @@
           {{ model[field] }}
         </template>
       </BasicForm>
+      <BasicTable @register="registerTable">
+        <template #action="{ record }">
+          <TableAction
+            :actions="[
+              {
+                label: '删除',
+                color: 'error',
+                //ifShow: getCheckPerm('lanuser-delete'),
+                onClick:handDelconfirm.bind(null, record),
+              },
+            ]"
+          />
+        </template>
+      </BasicTable>
     </div>
   </BasicModal>
 </template>
@@ -22,10 +36,19 @@
   import { useMessage } from '/@/hooks/web/useMessage';
   import { useI18n } from '/@/hooks/web/useI18n';
   import { getinnerByRyId, userShareAdd } from '/@/api/operate';
-
+  import { pageDataAuth, pageAuthList, delPageAuth } from '/@/api/statistics/index';
+  import { platformId, getUserInfo } from '/@/views/statistics/scene/data';
+  import { usePermissionStore } from '/@/store/modules/permission';
+  import {
+    BasicTable,
+    TableAction,
+    useTable,
+    BasicColumn,
+  } from '/@/components/Table';
+import { formatStrategyValues } from 'ant-design-vue/lib/vc-tree-select/utils/strategyUtil';
   const { t } = useI18n();
   export default defineComponent({
-    components: { BasicModal, BasicForm },
+    components: { BasicModal, BasicForm, BasicTable, TableAction },
     props: {
       userData: { type: Object },
     },
@@ -35,11 +58,14 @@
       const fileFlow = reactive({
         file: null,
       });
-      const { createMessage } = useMessage();
+      console.log('getUserInfo', getUserInfo.value, platformId.value);
+      const permissionStore = usePermissionStore();
+      const { getCheckPerm } = permissionStore;
+      const { createMessage, createConfirm } = useMessage();
       const optionsName = ref([]);
       const schemas: FormSchema[] = [
         {
-          field: 'id',
+          field: 'jyId',
           component: 'Input',
           show: false,
           label: 'id',
@@ -70,7 +96,7 @@
                 if(myData.ryNickName != ryNickName || !myData.ryNickName){
                   setFieldsValue({
                     ryNickName: res && res.data ? res.data.ryNickName : '',
-                    id: res && res.data ? res.data.id : '',
+                    jyId: res && res.data ? res.data.id : '',
                   });
                 }
               },
@@ -81,45 +107,10 @@
             span: 20,
           },
         },
-        // {
-        //   field: 'ryNo',
-        //   component: 'AutoComplete',
-        //   label: '人员编号',
-        //   required: true,
-        //   componentProps: {
-        //     filterOption: onFilterOption,
-        //     onSearch: onSearch,
-        //     onChange: (data) => {
-        //       setTimeout(() => {
-        //         const item = optionsName.value && optionsName.value.find((ele) => ele.ryNo == data);
-        //         setFieldsValue({
-        //           ryNickName: item && item.ryNickName ? item.ryNickName : '',
-        //           id: item && item.id ? item.id : '',
-        //         });
-        //       }, 100);
-        //     },
-        //   },
-        //   colProps: {
-        //     span: 20,
-        //   },
-        // },
         {
           field: 'ryNickName',
           component: 'Input',
           label: '姓名',
-          // rules: [
-          //   {
-          //     required: true,
-          //     // @ts-ignore
-          //     validator: async (rule, value) => {
-          //       if (!value) {
-          //         return Promise.reject('请输入正确的人员编号');
-          //       }
-          //       return Promise.resolve();
-          //     },
-          //     trigger: 'change',
-          //   },
-          // ],
           colProps: {
             span: 20,
           },
@@ -139,11 +130,67 @@
           span: 24,
         },
       });
-
+      const columns: BasicColumn[] = [
+        {
+          title: t('routes.staff.userName'),
+          dataIndex: 'ryNickName',
+          ellipsis: true,
+          width: 120,
+        },
+        {
+          title: '人员编号',
+          dataIndex: 'ryNo',
+          ellipsis: true,
+          width: 150,
+        },
+        {
+          title: '平台',
+          ellipsis: true,
+          dataIndex: 'platformName',
+          width: 80,
+        },
+        {
+          title: '操作',
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+          ifShow: true,
+          fixed: 'right',
+          flag: 'ACTION',
+          width: 120,
+        },
+      ];
+      const [registerTable, { reload }] = useTable({
+        api: pageAuthList,
+        title: '已分享列表',
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        // rowSelection: { type: 'checkbox',onChange: onSelectChange },
+        searchInfo: { platformId: platformId.value },
+        useSearchForm: false,
+        showTableSetting: true,
+        showIndexColumn:false,
+        rowKey: 'id',
+        immediate: true,
+        beforeFetch:(T)=>{
+          if(T.ctivated){
+            T.activatedStartTime = T.ctivated[0]
+            T.activatedEndTime = T.ctivated[1]
+          }
+          return T
+        },
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: false,
+      });
       onMounted(() => {});
       let addListFunc = () => {};
       const [register, { closeModal }] = useModalInner(async (data) => {
         console.log('option', data);
+        reload();
       });
       function onFilterOption(inputText: string, option) {
         console.log('option', inputText, option.value);
@@ -168,7 +215,10 @@
         const params = await validate();
         try {
           console.log('params', params);
-          await userShareAdd(params);
+          await pageDataAuth({
+            ...params,
+            pageAuth: 1,
+          });
           closeModal();
           resetFields();
           emit('ok');
@@ -177,16 +227,33 @@
           console.log('not passing', error);
         }
       };
-
+      function handDelconfirm(record) {
+        createConfirm({
+          iconType: 'warning',
+          title: '提示',
+          content: `确定删除?此操作无法撤销。`,
+          onOk: async () => {
+            await delPageAuth({
+              ...record,
+              pageAuth: 0,
+            });
+            createMessage.success('操作成功');
+            reload();
+          },
+        });
+      }
       return {
         register,
         schemas,
         registerForm,
+        handDelconfirm,
         modelRef,
         fileFlow,
         handleSubmit,
         addListFunc,
         resetFields,
+        registerTable,
+        getCheckPerm,
         t,
       };
     },

+ 13 - 0
src/views/statistics/scene/data.ts

@@ -0,0 +1,13 @@
+import { ref, computed } from 'vue';
+import { useUserStore } from '/@/store/modules/user';
+export const district = ref([]);
+export const cameraType = ref(null);
+export const platformId = ref(null);
+export const platformOptions = ref(null);
+export const jyType = ref([]);
+const userStore = useUserStore();
+export const getUserInfo = computed(() => {
+  const userinfo = userStore.getUserInfo || {};
+  if (userinfo.platformId) platformId.value = userinfo.platformId;
+  return userinfo;
+});

+ 45 - 35
src/views/statistics/scene/exportModal.vue

@@ -24,6 +24,8 @@
   import { useI18n } from '/@/hooks/web/useI18n';
   import { getinnerByRyId, userShareAdd } from '/@/api/operate';
   import { sceneGroupCount } from '/@/api/jyUserPlatform/index'; //roleLIstApi
+  import { exportSceneList } from '/@/api/statistics/index'; //roleLIstApi
+  import { district, jyType } from '/@/views/statistics/scene/data';
 
   const { t } = useI18n();
   export default defineComponent({
@@ -41,72 +43,63 @@
       const optionsName = ref([]);
       const schemas: FormSchema[] = [
         {
-          field: 'd3',
-          component: 'Select',
+          field: 'platformId',
+          component: 'Input',
+          show: false,
+          label: 'platformId',
+          required: false,
+        },
+        {
+          field: 'districtCodeList',
+          component: 'ApiTreeSelect',
           label: '地区',
           componentProps: {
-            options: [
-              {
-                label: '1个月',
-                value: 1,
-                key: '1',
-              },
-              {
-                label: '2个月',
-                value: 2,
-                key: '2',
-              },
-            ],
+            treeData: district,
+            listHeight: 200,
+            multiple: true,
+            treeNodeFilterProp: 'label',
+            showSearch: true,
           },
           colProps: {
             span: 20,
           },
         },
         {
-          field: 'd2',
+          field: 'jyType',
           component: 'Select',
           label: '警种',
           componentProps: {
-            options: [
-              {
-                label: '1个月',
-                value: 1,
-                key: '1',
-              },
-              {
-                label: '2个月',
-                value: 2,
-                key: '2',
-              },
-            ],
+            options: jyType,
+            listHeight: 200,
           },
           colProps: {
             span: 20,
           },
         },
         {
-          field: 'type',
+          field: 'cameraTypeList',
           label: '相机类型',
           component: 'ApiSelect',
           componentProps: {
-            style: { maxWidth: '250px' },
+            style: { maxWidth: '297px' },
             placeholder: '全部',
             api: sceneGroupCount,
+            mode: 'multiple',
             immediate: false,
             resultField: 'list',
             labelField: 'name',
             valueField: 'id',
             params: { type: 'camera' },
           },
-          colProps: {
-            xl: 12,
-            xxl: 12,
-          },
         },
         {
-          field: 'riq',
+          field: 'timeList',
           component: 'RangePicker',
           label: '时间',
+          componentProps: {
+            valueFormat: 'YYYY-MM-DD',
+            getCalendarContainer: (trigger) => trigger.parentNode,
+          },
           colProps: {
             span: 20,
           },
@@ -128,6 +121,23 @@
       let addListFunc = () => {};
       const [register, { closeModal }] = useModalInner(async (data) => {
         console.log('option', data);
+        setFieldsValue({
+          platformId: data.platformId,
+        });
+        updateSchema([
+          {
+            field: 'districtCodeList',
+            componentProps: {
+              treeData: data.district || [],
+            },
+          },
+          {
+            field: 'jyType',
+            componentProps: {
+              options: data.jyType || [],
+            },
+          },
+        ]);
       });
       function onFilterOption(inputText: string, option) {
         console.log('option', inputText, option.value);
@@ -152,7 +162,7 @@
         const params = await validate();
         try {
           console.log('params', params);
-          await userShareAdd(params);
+          await exportSceneList(params);
           closeModal();
           resetFields();
           emit('ok');

+ 141 - 47
src/views/statistics/scene/index.vue

@@ -3,53 +3,85 @@
     <div class="home flex justify-between">
       <div class="homeLeft" style="margin-bottom: 10px">
         <Select
-          v-model:value="value"
-          style="width: 100px; margin-right: 30px"
+          v-if="getUserInfo.roleId != 47"
+          v-model:value="platformId"
+          style="width: 100px; margin-right: 15px"
+          placeholder="全部平台"
+          :allowClear="getUserInfo.roleId == 1 || getUserInfo.roleId == 45"
+          :getPopupContainer="(trigger) => trigger.parentNode"
+          :options="platformOptions"
+          @change="handleChange"
+        />
+        <Select
+          v-model:value="cameraType"
+          style="min-width: 100px; margin-right: 30px"
           placeholder="全部相机"
           :options="options"
+          :getPopupContainer="(trigger) => trigger.parentNode"
           @change="handleChange"
         />
-        <span>当前账号采集总数:152 | 更新于 2025-09-22 04:11:27</span>
+        <span>当前账号采集总数:{{ userCount }} <span v-if="useruploadTime">| 更新于 {{ useruploadTime }}</span></span>
       </div>
-      <div class="homeright">
-        <a-button style="margin-right: 15px" type="primary" @click="openModal(true, { })">
+      <div v-if="getUserInfo.roleId != 47" class="homeright">
+        <a-button style="margin-right: 15px" type="primary" @click="openModal(true, { district, jyType, platformId })">
           查询并导出</a-button
         >
         <a-button @click="openAddModal(true, {})"> 页面权限</a-button>
       </div>
     </div>
     <GrowCard :loading="loading" :list="growCardList" class="enter-y" />
-    <div class="md:flex !my-4 enter-y">
+    <div class="page" v-if="loadingvalue == 2" :key="loading1">
+      <div v-if="pageAuth == 'admin'" class="md:flex !my-4 enter-y">
+        <lineEcharts2
+          :district="district"
+          :jyType="jyType"
+          :cameraType="cameraType"
+          :platformId="platformId"
+          :options="optionsList"
+          name="chartRef2"
+          class="md:w-1/2 w-full !md:mt-0 !mt-4 !md:mr-4"
+          @export="handleExport"
+          @change="Search"
+          :echartData="orderData"
+        />
+        <VisitSource
+          class="md:w-1/2 mx-4 w-full"
+          name="chartRef1"
+          :district="district"
+          :platformId="platformId"
+          :cameraType="cameraType"
+          :jyType="jyType"
+          @change="Search"
+          :propsData="echartData"
+          @export="handleExport"
+        />
+      </div>
       <lineEcharts2
-        :options="optionsList"
+        v-else
+        :district="district"
+        :platformId="platformId"
+        :cameraType="cameraType"
+        :jyType="jyType"
+        :hiddens="pageAuth != 'admin'"
         name="chartRef2"
-        class="md:w-1/2 w-full !md:mt-0 !mt-4 !md:mr-4"
+        class="!my-4 enter-y"
         @export="handleExport"
         @change="Search"
         :echartData="orderData"
       />
-      <VisitSource
-        class="md:w-1/2 mx-4 w-full"
-        name="chartRef1"
-        @change="Search"
-        :propsData="echartData"
+      <orderEchart
+        v-if="pageAuth == 'admin'"
+        title="地区分布"
+        :district="district"
+        :platformId="platformId"
+        :cameraType="cameraType"
+        :jyType="jyType"
+        class="!my-4 enter-y"
         @export="handleExport"
+        @change="Search"
+        :echartData="scenetData"
       />
     </div>
-    <lineEcharts2
-      name="chartRef2"
-      class="!my-4 enter-y"
-      @export="handleExport"
-      @change="Search"
-      :echartData="orderData"
-    />
-    <orderEchart
-      title="近半年场景新增趋势"
-      class="!my-4 enter-y"
-      @export="handleExport"
-      @change="Search"
-      :echartData="scenetData"
-    />
     <!-- <sceneEchart
       title="采集趋势"
       class="!my-4 enter-y"
@@ -62,8 +94,9 @@
 </template>
 <script lang="ts" setup>
   import { ref, onMounted, reactive } from 'vue';
-  import { sceneGroupCount } from '/@/api/jyUserPlatform/index'; //roleLIstApi
-  import { sceneTotal, sceneTrend } from '/@/api/statistics/index';
+  import { renameTreeFields } from '/@/utils/treeUtils';
+  import { sceneGroupCount, getDistrict, getJyType } from '/@/api/jyUserPlatform/index'; //roleLIstApi
+  import { sceneTotal, sceneTrend, platformList } from '/@/api/statistics/index';
   import VisitSource from '../components/VisitSource.vue';
   import lineEcharts2 from '../components/lineEcharts2.vue';
   import { useModal } from '/@/components/Modal';
@@ -71,13 +104,26 @@
   import exportModal from './exportModal.vue';
   import { Select } from 'ant-design-vue';
   import { GrowCardItem } from '../data';
+  import { getUserInfo } from '/@/views/statistics/scene/data';
   import GrowCard from '../components/GrowCard.vue';
   import sceneEchart from '../components/sceneEchart.vue';
   import orderEchart from '../components/orderEchart.vue';
+  import moment from 'moment';
+  //日期框国际化
+  import locale from 'ant-design-vue/es/date-picker/locale/zh_CN';
   const loading = ref(true);
+  const loadingvalue = ref(0);
+  const loading1 = ref(0);
   const growCardList = ref<GrowCardItem[]>([]);
-  const value = ref(null);
+  const district = ref([]);
+  const cameraType = ref(null);
+  const platformOptions = ref([]);
+  const jyType = ref([]);
+  const platformId = ref(null)
+  const pageAuth = ref('admin');
   const options = ref([]);
+  const userCount = ref(0);
+  const useruploadTime = ref(null);
   const optionsList = ref({
     region: [
       // { value: '', label: '全部地区' },
@@ -119,17 +165,17 @@
   });
   const [registerAdd, { openModal: openAddModal }] = useModal();
   const [register, { openModal }] = useModal();
+  moment.locale('zh-cn');
+  getOptions();
   onMounted(() => {
-    getData();
+    // getData();
     // getList();
   });
   async function getList() {
     let downlist = [],
       xdata = [];
-    const { kjList, kkList, ssList, ssobjList, sgList, sgobjList, yzlList } = await sceneTrend(
-      SearchData,
-    );
-    kjList.map((ele) => {
+    const { list, type } = await sceneTrend(SearchData);
+    list.map((ele) => {
       xdata.push(ele.groupKey);
       downlist.push(ele.count);
     });
@@ -151,15 +197,57 @@
     SearchData.type = dataType;
     getList();
   }
+  function getOptions() {
+    loading.value = true;
+    getDistrict({}).then((res) => {
+      let newlist = renameTreeFields(res, {
+        childrenList: 'children',
+        nameSn: 'label',
+        code: 'value',
+      });
+      district.value = newlist;
+      loadingvalue.value = loadingvalue.value + 1;
+    });
+    getJyType({}).then((res) => {
+      jyType.value = res && res!.map((ele) => ({ ...ele, label: ele.name, value: ele.code })) || [];
+      loadingvalue.value = loadingvalue.value + 1;
+    });
+    platformList({}).then((res) => {
+      platformOptions.value = res!.map((ele) => ({ ...ele, label: ele.platformName, value: ele.id }));
+      if(getUserInfo.value.platformId && (getUserInfo.value.roleId == 47 || getUserInfo.value.roleId == 48)){
+        platformId.value = getUserInfo.value.platformId
+        let item = platformOptions.value.find(item => item.id == getUserInfo.value.platformId)
+        pageAuth.value = item.pageAuth;
+      }else{
+        pageAuth.value = 'admin'
+      }
+      getData();
+    });
+  }
+  // 获取场景统计数据
   async function getData() {
     try {
-      loading.value = true;
-      const { totalSceneCount = 0, preMonthAddCount = 0, todayAddCount = 0 } = await sceneTotal();
+      // 调用API获取场景统计总数
+      const {
+        userSceneCount = 0,
+        updateTime,
+        todaySceneCount = 0,
+        timeSceneCount = 0,
+        totalSceneCount = 0,
+        totalUserCount = 0,
+        totalSceneUserCount = 0,
+      } = await sceneTotal({
+        cameraType: cameraType.value,
+        platformId: platformId.value
+      });
+      userCount.value = userSceneCount;
+      useruploadTime.value = updateTime;
+      // 构建统计卡片数据列表
       let list: GrowCardItem[] = [
         {
           title: '今日采集数量',
           icon: 'fxemoji:notchedrightsemi3dot',
-          value: totalSceneCount,
+          value: todaySceneCount,
           unit: '个',
           color: 'orange',
           action: '日',
@@ -167,7 +255,7 @@
         {
           title: '30日采集数量',
           icon: 'download-count|svg',
-          value: preMonthAddCount,
+          value: timeSceneCount,
           unit: '个',
           color: 'blue',
           action: '月',
@@ -175,28 +263,34 @@
         {
           title: '累计采集数量',
           icon: 'transaction|svg',
-          value: todayAddCount,
+          value: totalSceneCount,
           unit: '个',
           color: 'green',
           action: '年',
         },
-        {
+      ];
+      if (getUserInfo.value != 47) {
+        list.push({
           title: '总采集用户数/总用户数',
           icon: 'transaction|svg',
-          value: todayAddCount,
-          total: 1600,
+          value: totalSceneUserCount,
+          total: totalUserCount,
           unit: '个',
           color: 'green',
           action: '年',
-        },
-      ];
+        });
+      }
       loading.value = false;
+      // 更新统计卡片列表
       growCardList.value = list;
     } catch (error) {
       loading.value = false;
     }
   }
-  function handleChange(val) {
-    console.log('val', val);
+  function handleChange(val, item) {
+    console.log('val', val, item);
+    pageAuth.value = item.pageAuth;
+    loading1.value += 1;
+    getData();
   }
 </script>