From 796f1fce7951ca1dd4ba5785f25d86bf5ca9dcd5 Mon Sep 17 00:00:00 2001
From: 刘嘉威 <daidaibg@163.com>
Date: 星期四, 27 十月 2022 17:23:27 +0800
Subject: [PATCH] feat:增加无缝轮播组件 增加左下 右下组件

---
 src/views/setting.vue                              |   45 ++
 types/global.d.ts                                  |    2 
 src/components/seamless-scroll/index.ts            |    2 
 src/views/index/left-bottom.vue                    |  228 ++++++++++++
 components.d.ts                                    |    2 
 src/api/modules/index.ts                           |    4 
 src/views/index/right-bottom.vue                   |  193 ++++++++++
 src/views/index/index.vue                          |    3 
 src/components/seamless-scroll/seamless-scroll.vue |  407 ++++++++++++++++++++++
 src/assets/css/variable.scss                       |    1 
 src/components/empty-com/index.ts                  |    2 
 src/components/empty-com/empty-com.vue             |    9 
 src/mock/mock-index.ts                             |   81 +++
 src/stores/setting/setting.ts                      |   53 ++
 src/assets/css/main.scss                           |   44 ++
 15 files changed, 1,038 insertions(+), 38 deletions(-)

diff --git a/components.d.ts b/components.d.ts
index fba7b29..00bed56 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -12,10 +12,12 @@
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
     ElRadio: typeof import('element-plus/es')['ElRadio']
     ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
+    EmptyCom: typeof import('./src/components/empty-com/empty-com.vue')['default']
     ItemWrap: typeof import('./src/components/item-wrap/item-wrap.vue')['default']
     MessageContent: typeof import('./src/components/Plugins/MessageContent/index.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
     ScaleScreen: typeof import('./src/components/scale-screen/scale-screen.vue')['default']
+    SeamlessScroll: typeof import('./src/components/seamless-scroll/seamless-scroll.vue')['default']
   }
 }
diff --git a/src/api/modules/index.ts b/src/api/modules/index.ts
index 7cff390..e0e896c 100644
--- a/src/api/modules/index.ts
+++ b/src/api/modules/index.ts
@@ -4,8 +4,8 @@
     "centerMap":"/bigscreen/centerMap",
     "centerBottom":"/bigscreen/installationPlan",
 
-    // 'big3':"/bigscreen/sbtx", //璁惧鎻愰啋
+    'leftBottom':"/bigscreen/leftBottom", //鍧愪笅
     'rightTop':"/bigscreen/alarmNum", //鎶ヨ娆℃暟
-    // 'big5':'/bigscreen/ssyj',//瀹炴椂棰勮 
+    'rightBottom':'/bigscreen/rightBottom',//鍙充笅 
     'rightCenter':'/bigscreen/ranking',// 鎶ヨ鎺掑悕
 }
\ No newline at end of file
diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index fbc751c..08381e3 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -51,4 +51,48 @@
     .el-message__content {
       color: var(--yh-text-color-primary);
     }
+  }
+
+  .beautify-scroll-def {
+    overflow-y: auto;
+  
+    &::-webkit-scrollbar-thumb {
+      //婊氬姩鏉$殑璁剧疆
+      background-color: rgba(14, 59, 150, 0);
+      background-clip: padding-box;
+      border-radius: 4px;
+    }
+  
+    &:hover {
+      &::-webkit-scrollbar-thumb {
+        //婊氬姩鏉$殑璁剧疆
+        background-color: rgba(14, 59, 150, 0.5);
+        background-clip: padding-box;
+        border-radius: 4px;
+      }
+    }
+  
+    &::-webkit-scrollbar-track-piece {
+      //婊氬姩鏉″嚬妲界殑棰滆壊锛岃繕鍙互璁剧疆杈规灞炴��
+      background-color: transparent;
+    }
+  
+    &::-webkit-scrollbar {
+      //婊氬姩鏉$殑瀹藉害
+      width: 8px;
+      height: 8px;
+    }
+  
+  
+  
+    &::-webkit-scrollbar-thumb:hover {
+      background-color: rgba(14, 59, 150, .8);
+    }
+  }
+
+  .text-content {
+    width: 100%;
+    display: flex;
+    min-height: calc(100% - 60px);
+    justify-content: space-between;
   }
\ No newline at end of file
diff --git a/src/assets/css/variable.scss b/src/assets/css/variable.scss
index e69de29..0dec46e 100644
--- a/src/assets/css/variable.scss
+++ b/src/assets/css/variable.scss
@@ -0,0 +1 @@
+$primary-color: #1890ff;
\ No newline at end of file
diff --git a/src/components/empty-com/empty-com.vue b/src/components/empty-com/empty-com.vue
new file mode 100644
index 0000000..b87eb83
--- /dev/null
+++ b/src/components/empty-com/empty-com.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts"></script>
+
+<template>
+  <div>
+    <slot></slot>
+  </div>
+</template>
+
+<style scoped lang="scss"></style>
diff --git a/src/components/empty-com/index.ts b/src/components/empty-com/index.ts
new file mode 100644
index 0000000..2cf8d9f
--- /dev/null
+++ b/src/components/empty-com/index.ts
@@ -0,0 +1,2 @@
+import EmptyCom from "./empty-com.vue"
+export default EmptyCom
\ No newline at end of file
diff --git a/src/components/seamless-scroll/index.ts b/src/components/seamless-scroll/index.ts
new file mode 100644
index 0000000..a422cf6
--- /dev/null
+++ b/src/components/seamless-scroll/index.ts
@@ -0,0 +1,2 @@
+import SeamlessScroll from "./seamless-scroll.vue"
+export default SeamlessScroll
\ No newline at end of file
diff --git a/src/components/seamless-scroll/seamless-scroll.vue b/src/components/seamless-scroll/seamless-scroll.vue
new file mode 100644
index 0000000..cf42f6a
--- /dev/null
+++ b/src/components/seamless-scroll/seamless-scroll.vue
@@ -0,0 +1,407 @@
+<script setup lang="ts">
+import {
+  computed,
+  defineComponent,
+  onBeforeMount,
+  onMounted,
+  ref,
+  watch,
+  nextTick,
+} from "vue";
+import type { CSSProperties } from "vue";
+import throttle from "lodash/throttle";
+type propsType = {
+  modelValue?: boolean;
+  list: Array<any>;
+  step?: number;
+  limitScrollNum?: number;
+  hover?: boolean;
+  direction?: string;
+  singleHeight?: number;
+  singleWidth?: number;
+  singleWaitTime?: number;
+  isRemUnit?: boolean;
+  isWatch?: boolean;
+  delay?: number;
+  ease?: any;
+  count?: number;
+  copyNum?: number;
+  wheel?: boolean;
+  singleLine?: boolean;
+};
+const props = withDefaults(defineProps<propsType>(), {
+  // 鏄惁寮�鍚嚜鍔ㄦ粴鍔�
+  modelValue: true,
+  // 鍘熷鏁版嵁鍒楄〃
+  list: () => [],
+  // 姝ヨ繘閫熷害锛宻tep 闇�鏄崟姝ュぇ灏忕殑绾︽暟
+  step: 1,
+  // 寮�鍚粴鍔ㄧ殑鏁版嵁閲�
+  limitScrollNum: 3,
+  // 鏄惁寮�鍚紶鏍囨偓鍋�
+  hover: false,
+  // 鎺у埗婊氬姩鏂瑰悜
+  direction: "up",
+  // 鍗曟杩愬姩鍋滄鐨勯珮搴�
+  singleHeight: 0,
+  // 鍗曟杩愬姩鍋滄鐨勫搴�
+  singleWidth: 0,
+  // 鍗曟鍋滄绛夊緟鏃堕棿 (榛樿鍊� 1000ms)
+  singleWaitTime: 1000,
+  // 鏄惁寮�鍚� rem 搴﹂噺
+  isRemUnit: false,
+  // 寮�鍚暟鎹洿鏂扮洃鍚�
+  isWatch: true,
+  // 鍔ㄧ敾鏃堕棿
+  delay: 0,
+  // 鍔ㄧ敾鏂瑰紡
+  ease: "ease-in",
+  // 鍔ㄧ敾寰幆娆℃暟锛�-1 琛ㄧず涓�鐩村姩鐢�
+  count: -1,
+  // 鎷疯礉鍑犱唤婊氬姩鍒楄〃
+  copyNum: 1,
+  // 寮�鍚紶鏍囨偓鍋滄椂鏀寔婊氳疆婊氬姩
+  wheel: false,
+  // 鍚敤鍗曡婊氬姩
+  singleLine: false,
+});
+interface Emits {
+  (event: "count", _count: number): void;
+  (event: "stop", _count: number): void;
+}
+const emit = defineEmits<Emits>();
+const scrollRef = ref(null);
+const slotListRef = ref<HTMLDivElement | null>(null);
+const realBoxRef = ref<HTMLDivElement | null>(null);
+const reqFrame = ref<number | null>(null);
+const singleWaitTimeout = ref<TimeProp | null>(null);
+const realBoxWidth = ref(0);
+const realBoxHeight = ref(0);
+const xPos = ref(0);
+const yPos = ref(0);
+const isHover = ref(false);
+const _count = ref(0);
+const isScroll = computed(() =>
+  props.list ? props.list.length >= props.limitScrollNum : false
+);
+const realBoxStyle = computed(() => {
+  return {
+    width: realBoxWidth.value ? `${realBoxWidth.value}px` : "auto",
+    transform: `translate(${xPos.value}px,${yPos.value}px)`,
+    transition: `all ${
+      typeof props.ease === "string"
+        ? props.ease
+        : "cubic-bezier(" +
+          props.ease.x1 +
+          "," +
+          props.ease.y1 +
+          "," +
+          props.ease.x2 +
+          "," +
+          props.ease.y2 +
+          ")"
+    } ${props.delay}ms`,
+    overflow: "hidden",
+    display: props.singleLine ? "flex" : "block",
+  };
+});
+const isHorizontal = computed(
+  () => props.direction == "left" || props.direction == "right"
+);
+
+function dataWarm(list: any) {
+  if (list && typeof list !== "boolean" && list.length > 100) {
+    console.warn(
+      `鏁版嵁杈惧埌浜�${list.length}鏉℃湁鐐瑰鍝,鍙兘浼氶�犳垚閮ㄥ垎鑰佹棫娴忚鍣ㄥ崱椤裤�俙
+    );
+  }
+}
+const floatStyle = computed<CSSProperties>(() => {
+  return isHorizontal.value
+    ? {
+        float: "left",
+        overflow: "hidden",
+        display: props.singleLine ? "flex" : "block",
+        flexShrink: props.singleLine ? 0 : 1,
+      }
+    : { overflow: "hidden" };
+});
+const baseFontSize = computed(() => {
+  return props.isRemUnit
+    ? parseInt(
+        globalThis.window.getComputedStyle(
+          globalThis.document.documentElement,
+          null
+        ).fontSize
+      )
+    : 1;
+});
+const realSingleStopWidth = computed(
+  () => props.singleWidth * baseFontSize.value
+);
+
+const realSingleStopHeight = computed(
+  () => props.singleHeight * baseFontSize.value
+);
+
+const step = computed(() => {
+  let singleStep: number;
+  let _step = props.step;
+  if (isHorizontal.value) {
+    singleStep = realSingleStopWidth.value;
+  } else {
+    singleStep = realSingleStopHeight.value;
+  }
+  if (singleStep > 0 && singleStep % _step > 0) {
+    console.error(
+      "濡傛灉璁剧疆浜嗗崟姝ユ粴鍔紝step 闇�鏄崟姝ュぇ灏忕殑绾︽暟锛屽惁鍒欐棤娉曚繚璇佸崟姝ユ粴鍔ㄧ粨鏉熺殑浣嶇疆鏄惁鍑嗙‘銆倊~~~~"
+    );
+  }
+  return _step;
+});
+
+const cancle = () => {
+  cancelAnimationFrame(reqFrame.value as number);
+  reqFrame.value = null;
+};
+const animation = (
+  _direction: "up" | "down" | "left" | "right",
+  _step: number,
+  isWheel?: boolean
+) => {
+  // console.log("animation",_direction,_step,isWheel);
+  reqFrame.value = requestAnimationFrame(function () {
+    const h = realBoxHeight.value / 2;
+    const w = realBoxWidth.value / 2;
+    if (_direction === "up") {
+      if (Math.abs(yPos.value) >= h) {
+        yPos.value = 0;
+        _count.value += 1;
+        emit("count", _count.value);
+      }
+      yPos.value -= _step;
+    } else if (_direction === "down") {
+      if (yPos.value >= 0) {
+        yPos.value = h * -1;
+        _count.value += 1;
+        emit("count", _count.value);
+      }
+      yPos.value += _step;
+    } else if (_direction === "left") {
+      if (Math.abs(xPos.value) >= w) {
+        xPos.value = 0;
+        _count.value += 1;
+        emit("count", _count.value);
+      }
+      xPos.value -= _step;
+    } else if (_direction === "right") {
+      if (xPos.value >= 0) {
+        xPos.value = w * -1;
+        _count.value += 1;
+        emit("count", _count.value);
+      }
+      xPos.value += _step;
+    }
+    if (isWheel) {
+      return;
+    }
+    let { singleWaitTime } = props;
+    if (singleWaitTimeout.value) {
+      clearTimeout(singleWaitTimeout.value);
+    }
+    if (!!realSingleStopHeight.value) {
+      if (Math.abs(yPos.value) % realSingleStopHeight.value < _step) {
+        singleWaitTimeout.value = setTimeout(() => {
+          move();
+        }, singleWaitTime);
+      } else {
+        move();
+      }
+    } else if (!!realSingleStopWidth.value) {
+      if (Math.abs(xPos.value) % realSingleStopWidth.value < _step) {
+        singleWaitTimeout.value = setTimeout(() => {
+          move();
+        }, singleWaitTime);
+      } else {
+        move();
+      }
+    } else {
+      move();
+    }
+  });
+};
+const move = () => {
+  cancle();
+  if (isHover.value || !isScroll.value || _count.value === props.count) {
+    emit("stop", _count.value);
+    _count.value = 0;
+    return;
+  }
+  animation(
+    props.direction as "up" | "down" | "left" | "right",
+    step.value,
+    false
+  );
+};
+const initMove = () => {
+  dataWarm(props.list);
+  if (isHorizontal.value) {
+    let slotListWidth = (slotListRef.value as HTMLDivElement).offsetWidth;
+    slotListWidth = slotListWidth * 2 + 1;
+    realBoxWidth.value = slotListWidth;
+  }
+  if (isScroll.value) {
+    realBoxHeight.value = (realBoxRef.value as HTMLDivElement).offsetHeight;
+    if (props.modelValue) {
+      move();
+    }
+  } else {
+    cancle();
+    yPos.value = xPos.value = 0;
+  }
+  // console.log("initMove","isHorizontal",isHorizontal.value,"isScroll",isScroll.value,realBoxRef.value?.offsetHeight);
+};
+const startMove = () => {
+  isHover.value = false;
+  move();
+};
+
+const stopMove = () => {
+  isHover.value = true;
+  if (singleWaitTimeout.value) {
+    clearTimeout(singleWaitTimeout.value);
+  }
+  cancle();
+};
+
+const hoverStop = computed(
+  () => props.hover && props.modelValue && isScroll.value
+);
+const throttleFunc = throttle((e: WheelEvent) => {
+  cancle();
+  const singleHeight = !!realSingleStopHeight.value
+    ? realSingleStopHeight.value
+    : 15;
+  if (e.deltaY < 0) {
+    animation("down", singleHeight, true);
+  }
+  if (e.deltaY > 0) {
+    animation("up", singleHeight, true);
+  }
+}, 30);
+
+const onWheel = (e: WheelEvent) => {
+  throttleFunc(e);
+};
+const reset = () => {
+  cancle();
+  isHover.value = false;
+  initMove();
+};
+const Reset = () => {
+  reset();
+};
+defineExpose({
+  Reset,
+});
+
+watch(
+  () => props.list,
+  () => {
+    if (props.isWatch) {
+      nextTick(() => {
+        reset();
+      });
+    }
+  },
+  {
+    deep: true,
+  }
+);
+
+watch(
+  () => props.modelValue,
+  (newValue) => {
+    if (newValue) {
+      startMove();
+    } else {
+      stopMove();
+    }
+  }
+);
+
+watch(
+  () => props.count,
+  (newValue) => {
+    if (newValue !== 0) {
+      startMove();
+    }
+  }
+);
+
+onBeforeMount(() => {
+  cancle();
+  clearTimeout(singleWaitTimeout.value as unknown as number);
+});
+
+onMounted(() => {
+  if (isScroll.value) {
+    initMove();
+  }
+});
+</script>
+
+<template>
+  <div
+    v-if="props.wheel && props.hover"
+    ref="realBoxRef"
+    :style="realBoxStyle"
+    @mouseenter="
+      () => {
+        hoverStop && stopMove();
+      }
+    "
+    @mouseleave="
+      () => {
+        hoverStop && startMove();
+      }
+    "
+    @wheel="
+      (e) => {
+        hoverStop && onWheel(e);
+      }
+    "
+  >
+    <div ref="slotListRef" :style="floatStyle">
+      <slot></slot>
+    </div>
+    <div :style="floatStyle">
+      <slot></slot>
+    </div>
+  </div>
+
+  <div
+    v-else
+    :style="realBoxStyle"
+    ref="realBoxRef"
+    @mouseenter="
+      () => {
+        hoverStop && stopMove();
+      }
+    "
+    @mouseleave="
+      () => {
+        hoverStop && startMove();
+      }
+    "
+  >
+    <div ref="slotListRef" :style="floatStyle">
+      <slot></slot>
+    </div>
+    <div :style="floatStyle">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss"></style>
diff --git a/src/mock/mock-index.ts b/src/mock/mock-index.ts
index 72f33fb..4119b12 100644
--- a/src/mock/mock-index.ts
+++ b/src/mock/mock-index.ts
@@ -57,6 +57,31 @@
             return a
         }
     },
+    //宸︿笅
+    {
+        url: "/bigscreen/leftBottom",
+        type: "get",
+        response: () => {
+            const a = Mock.mock({
+                success: true,
+                data: {
+                    "list|20": [
+                        {
+                            provinceName: "@province()",
+                            cityName: '@city()',
+                            countyName: "@county()",
+                            createTime: "@datetime('yyyy-MM-dd HH:mm:ss')",
+                            deviceId: "6c512d754bbcd6d7cd86abce0e0cac58",
+                            "gatewayno|+1": 10000,
+                            "onlineState|1": [0, 1],
+
+                        }
+                    ]
+                }
+            })
+            return a
+        }
+    },
     //鍙充笂
     {
         url: "/bigscreen/alarmNum",
@@ -82,23 +107,51 @@
         url: "/bigscreen/ranking",
         type: "get",
         response: () => {
-            let num =Mock.mock({"list|80":[{ value:"@integer(50,1000)",name:"@city()"}]}).list
+            let num = Mock.mock({ "list|80": [{ value: "@integer(50,1000)", name: "@city()" }] }).list
             //   console.log("ranking",num);
-              let newNum:any =[],numObj:any ={}
-              num.map((item:any )=>{
-                if(!numObj[item.name] && newNum.length<8){
-                    numObj[item.name] =true
+            let newNum: any = [], numObj: any = {}
+            num.map((item: any) => {
+                if (!numObj[item.name] && newNum.length < 8) {
+                    numObj[item.name] = true
                     newNum.push(item)
                 }
-              })
-              let arr = newNum.sort((a:any ,b:any )=>{
-                return b.value-a.value
-              })
-              let a ={
-                  success:true,
-                  data:arr
-              }
-              return a
+            })
+            let arr = newNum.sort((a: any, b: any) => {
+                return b.value - a.value
+            })
+            let a = {
+                success: true,
+                data: arr
+            }
+            return a
+        }
+    },
+    //鍙充笅
+    {
+        url: "/bigscreen/rightBottom",
+        type: "get",
+        response: () => {
+            const a = Mock.mock({
+                success: true,
+                data: {
+                    "list|40": [{
+                        alertdetail: "@csentence(5,10)",
+                        "alertname|1": ["姘存蹈鍛婅", "鍚勭鎶ヨ"],
+                        alertvalue: "@float(60, 200)",
+                        createtime: "2022-04-19 08:38:33",
+                        deviceid: null,
+                        "gatewayno|+1": 10000,
+                        phase: "A1",
+                        sbInfo: "@csentence(10,18)",
+                        "terminalno|+1": 100,
+                        provinceName: "@province()",
+                        cityName: '@city()',
+                        countyName: "@county()",
+                    }],
+
+                }
+            })
+            return a
         }
     },
     //瀹夎璁″垝
diff --git a/src/stores/setting/setting.ts b/src/stores/setting/setting.ts
index fc8b59a..090aa01 100644
--- a/src/stores/setting/setting.ts
+++ b/src/stores/setting/setting.ts
@@ -1,28 +1,51 @@
-import { ref, computed } from 'vue'
+import { ref, computed, reactive } from 'vue'
 import { defineStore } from 'pinia'
 // import { storeToRefs } from 'pinia';
 export const useSettingStore = defineStore('setting', () => {
   const settingShow = ref(false);//璁剧疆寮圭獥鏄鹃殣
   const isScale = ref(false);//鏄惁杩涜鍏ㄥ眬閫傞厤
-
-  const setSettingShow = (flag:boolean)=>{
-    settingShow.value=flag
+  const indexConfig = ref({
+    leftBottomSwiper: true,//宸﹁疆鎾�
+    rightBottomSwiper: true,//鍙充笅杞挱
+  })
+  const defaultOption = ref({
+    step: 4, // 鏁板�艰秺澶ч�熷害婊氬姩瓒婂揩
+    hover: true, // 鏄惁寮�鍚紶鏍囨偓鍋渟top
+    wheel: false,//鍦ㄥ紑鍚紶鏍囨偓鍋滅殑鎯呭喌涓嬫槸鍚﹀紑鍚粴杞粴鍔紝榛樿涓嶅紑鍚�
+    openWatch: true, // 寮�鍚暟鎹疄鏃剁洃鎺у埛鏂癲om
+    direction: 1, // 0鍚戜笅 1鍚戜笂 2鍚戝乏 3鍚戝彸
+    limitScrollNum: 4, // 寮�濮嬫棤缂濇粴鍔ㄧ殑鏁版嵁閲� this.dataList.length
+    singleHeight: 0, // 鍗曟杩愬姩鍋滄鐨勯珮搴�(榛樿鍊�0鏄棤缂濅笉鍋滄鐨勬粴鍔�) direction => 0/1
+    singleWidth: 0, // 鍗曟杩愬姩鍋滄鐨勫搴�(榛樿鍊�0鏄棤缂濅笉鍋滄鐨勬粴鍔�) direction => 2/3
+    singleWaitTime: 3000 // 鍗曟杩愬姩鍋滄鐨勬椂闂�(榛樿鍊�1000ms)
+  })
+  const setSettingShow = (flag: boolean) => {
+    settingShow.value = flag
   }
-  const setIsScale = (flag:boolean)=>{
-    isScale.value=flag
+  const setIsScale = (flag: boolean) => {
+    isScale.value = flag
     setSettingData()
   }
-  const initSetting=()=>{
-    let settingData:any = localStorage.getItem('loftv-settingData')
-    if(settingData){
-        settingData=JSON.parse(settingData)
-        setIsScale(settingData.isScale)
+  const setIndexConfig = (Config: any) => {
+    indexConfig.value = Config
+    localStorage.setItem('loftv-indexConfig', JSON.stringify(indexConfig.value))
+  }
+  const initSetting = () => {
+    let settingData: any = localStorage.getItem('loftv-settingData')
+    if (settingData) {
+      settingData = JSON.parse(settingData)
+      setIsScale(settingData.isScale)
+    }
+    let settingIndexConfig: any = localStorage.getItem('loftv-indexConfig')
+    if (settingIndexConfig) {
+      settingIndexConfig = JSON.parse(settingIndexConfig)
+      setIndexConfig(settingIndexConfig)
     }
   }
-  const setSettingData=()=>{
-    localStorage.setItem('loftv-settingData',JSON.stringify({
-        isScale:isScale.value
+  const setSettingData = () => {
+    localStorage.setItem('loftv-settingData', JSON.stringify({
+      isScale: isScale.value
     }))
   }
-  return { settingShow, setSettingShow,isScale ,setIsScale,initSetting,setSettingData}
+  return { settingShow, setSettingShow, isScale, setIsScale, initSetting, setSettingData, defaultOption, indexConfig, setIndexConfig }
 })
diff --git a/src/views/index/index.vue b/src/views/index/index.vue
index 1fec044..defb1fa 100644
--- a/src/views/index/index.vue
+++ b/src/views/index/index.vue
@@ -2,6 +2,7 @@
 import ItemWrap from "@/components/item-wrap";
 import LeftTop from "./left-top.vue";
 import LeftCenter from "./left-center.vue";
+import LeftBottom from "./left-bottom.vue";
 import CenterMap from "./center-map.vue";
 import CenterBottom from "./center-bottom.vue";
 import RightTop from "./right-top.vue";
@@ -32,7 +33,7 @@
         title="璁惧鎻愰啋"
         style="padding: 0 10px 16px 10px"
       >
-        <!-- <LeftBottom /> -->
+        <LeftBottom />
       </ItemWrap>
     </div>
     <div class="contetn_center">
diff --git a/src/views/index/left-bottom.vue b/src/views/index/left-bottom.vue
new file mode 100644
index 0000000..b11f10a
--- /dev/null
+++ b/src/views/index/left-bottom.vue
@@ -0,0 +1,228 @@
+<script setup lang="ts">
+import { currentGET } from "@/api";
+import SeamlessScroll from "@/components/seamless-scroll";
+import { computed, onMounted, reactive } from "vue";
+import { useSettingStore } from "@/stores";
+import { storeToRefs } from "pinia";
+import EmptyCom from "@/components/empty-com"
+const settingStore = useSettingStore();
+const { defaultOption,indexConfig } = storeToRefs(settingStore);
+const state = reactive<any>({
+  list: [],
+  defaultOption: {
+    ...defaultOption.value,
+    singleHeight: 256,
+    limitScrollNum: 4,
+  },
+  scroll: true,
+});
+
+const getData = () => {
+  currentGET("leftBottom", { limitNum: 20 }).then((res) => {
+    console.log("璁惧鎻愰啋", res);
+    if (res.success) {
+      state.list = res.data.list;
+    } else {
+      window.$message({
+        text: res.msg,
+        type: "warning",
+      });
+    }
+  });
+};
+const addressHandle = (item: any) => {
+  let name = item.provinceName;
+  if (item.cityName) {
+    name += "/" + item.cityName;
+    if (item.countyName) {
+      name += "/" + item.countyName;
+    }
+  }
+  return name;
+};
+const comName = computed(()=>{
+    if(indexConfig.value.leftBottomSwiper){
+        return SeamlessScroll
+    }else{
+        return EmptyCom
+    }
+})
+onMounted(() => {
+  getData();
+});
+</script>
+
+<template>
+  <div class="left_boottom_wrap beautify-scroll-def"  :class="{ 'overflow-y-auto': !indexConfig.leftBottomSwiper }">
+    <component
+     :is="comName"
+      :list="state.list"
+      v-model="state.scroll"
+      :singleHeight="state.defaultOption.singleHeight"
+      :step="state.defaultOption.step"
+      :limitScrollNum="state.defaultOption.limitScrollNum"
+      :hover="state.defaultOption.hover"
+      :singleWaitTime="state.defaultOption.singleWaitTime"
+      :wheel="state.defaultOption.wheel"
+    >
+      <ul class="left_boottom">
+        <li class="left_boottom_item" v-for="(item, i) in state.list" :key="i">
+          <span class="orderNum doudong">{{ i + 1 }}</span>
+          <div class="inner_right">
+            <div class="dibu"></div>
+            <div class="flex">
+              <div class="info">
+                <span class="labels">璁惧ID锛�</span>
+                <span class="text-content zhuyao doudong wangguan">
+                  {{ item.gatewayno }}</span
+                >
+              </div>
+              <div class="info">
+                <span class="labels">鏃堕棿锛�</span>
+                <span class="text-content" style="font-size: 12px">
+                  {{ item.createTime }}</span
+                >
+              </div>
+            </div>
+
+            <span
+              class="types doudong"
+              :class="{
+                typeRed: item.onlineState == 0,
+                typeGreen: item.onlineState == 1,
+              }"
+              >{{ item.onlineState == 1 ? "涓婄嚎" : "涓嬬嚎" }}</span
+            >
+
+            <div class="info addresswrap">
+              <span class="labels">鍦板潃锛�</span>
+              <span class="text-content ciyao" style="font-size: 12px">
+                {{ addressHandle(item) }}</span
+              >
+            </div>
+          </div>
+        </li>
+      </ul>
+    </component>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.left_boottom_wrap {
+  overflow: hidden;
+  width: 100%;
+  height: 100%;
+}
+
+.doudong {
+  overflow: hidden;
+  backface-visibility: hidden;
+}
+
+.overflow-y-auto {
+  overflow-y: auto;
+}
+
+.left_boottom {
+  width: 100%;
+  height: 100%;
+
+  .left_boottom_item {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 8px;
+    font-size: 14px;
+    margin: 10px 0;
+    .orderNum {
+      margin: 0 16px 0 -20px;
+    }
+
+    .info {
+      margin-right: 10px;
+      display: flex;
+      align-items: center;
+      color: #fff;
+
+      .labels {
+        flex-shrink: 0;
+        font-size: 12px;
+        color: rgba(255, 255, 255, 0.6);
+      }
+
+      .zhuyao {
+        color: $primary-color;
+        font-size: 15px;
+      }
+
+      .ciyao {
+        color: rgba(255, 255, 255, 0.8);
+      }
+
+      .warning {
+        color: #e6a23c;
+        font-size: 15px;
+      }
+    }
+
+    .inner_right {
+      position: relative;
+      height: 100%;
+      width: 380px;
+      flex-shrink: 0;
+      line-height: 1;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      flex-wrap: wrap;
+      .dibu {
+        position: absolute;
+        height: 2px;
+        width: 104%;
+        background-image: url("@/assets/img/zuo_xuxian.png");
+        bottom: -10px;
+        left: -2%;
+        background-size: cover;
+      }
+      .addresswrap {
+        width: 100%;
+        display: flex;
+        margin-top: 8px;
+      }
+    }
+
+    .wangguan {
+      color: #1890ff;
+      font-weight: 900;
+      font-size: 15px;
+      width: 80px;
+      flex-shrink: 0;
+    }
+
+    .time {
+      font-size: 12px;
+      // color: rgba(211, 210, 210,.8);
+      color: #fff;
+    }
+
+    .address {
+      font-size: 12px;
+      cursor: pointer;
+      // @include text-overflow(1);
+    }
+
+    .types {
+      width: 30px;
+      flex-shrink: 0;
+    }
+
+    .typeRed {
+      color: #fc1a1a;
+    }
+
+    .typeGreen {
+      color: #29fc29;
+    }
+  }
+}
+</style>
diff --git a/src/views/index/right-bottom.vue b/src/views/index/right-bottom.vue
index 7df5872..751cbd6 100644
--- a/src/views/index/right-bottom.vue
+++ b/src/views/index/right-bottom.vue
@@ -1,13 +1,198 @@
-<script setup lang='ts'>
+<script setup lang="ts">
+import { currentGET } from "@/api";
+import SeamlessScroll from "@/components/seamless-scroll";
+import { computed, onMounted, reactive } from "vue";
+import { useSettingStore } from "@/stores";
+import { storeToRefs } from "pinia";
+import EmptyCom from "@/components/empty-com";
+const settingStore = useSettingStore();
+const { defaultOption, indexConfig } = storeToRefs(settingStore);
+const state = reactive<any>({
+  list: [],
+  defaultOption: {
+    ...defaultOption.value,
+    singleHeight: 252,
+    limitScrollNum: 3,
+    // step:3
+  },
+  scroll: true,
 
+});
+
+const getData = () => {
+  currentGET("rightBottom", { limitNum: 20 }).then((res) => {
+    console.log("鍙充笅", res);
+    if (res.success) {
+      state.list = res.data.list;
+    } else {
+      window.$message({
+        text: res.msg,
+        type: "warning",
+      });
+    }
+  });
+};
+
+const comName = computed(() => {
+  if (indexConfig.value.rightBottomSwiper) {
+    return SeamlessScroll;
+  } else {
+    return EmptyCom;
+  }
+});
+function montionFilter (val:any) {
+    // console.log(val);
+    return val ? Number(val).toFixed(2) : '--'
+}
+const handleAddress=(item:any)=>{
+  return `${ item.provinceName }/${item.cityName }/${item.countyName}`
+}
+onMounted(() => {
+  getData();
+});
 </script>
 
 <template>
-  <div class=''>
+  <div
+    class="right_bottom_wrap beautify-scroll-def"
+    :class="{ 'overflow-y-auto': !indexConfig.rightBottomSwiper }"
+  >
+    <component
+      :is="comName"
+      :list="state.list"
+      v-model="state.scroll"
+      :singleHeight="state.defaultOption.singleHeight"
+      :step="state.defaultOption.step"
+      :limitScrollNum="state.defaultOption.limitScrollNum"
+      :hover="state.defaultOption.hover"
+      :singleWaitTime="state.defaultOption.singleWaitTime"
+      :wheel="state.defaultOption.wheel"
+    >
+      <ul class="right_bottom">
+        <li class="right_center_item" v-for="(item, i) in state.list" :key="i">
+          <span class="orderNum">{{ i + 1 }}</span>
+          <div class="inner_right">
+            <div class="dibu"></div>
+            <div class="flex">
+              <div class="info">
+                <span class="labels">璁惧ID锛�</span>
+                <span class="text-content zhuyao"> {{ item.gatewayno }}</span>
+              </div>
+              <div class="info">
+                <span class="labels">鍨嬪彿锛�</span>
+                <span class="text-content"> {{ item.terminalno }}</span>
+              </div>
+              <div class="info">
+                <span class="labels">鍛婅鍊硷細</span>
+                <span class="text-content warning">
+                  {{  montionFilter(item.alertvalue) }}</span
+                >
+              </div>
+            </div>
 
+            <div class="flex">
+              <div class="info">
+                <span class="labels shrink-0"> 鍦板潃锛�</span>
+                <span class=" ciyao truncate" style="font-size: 12px;width: 220px;" :title="handleAddress(item)">
+                  {{ handleAddress(item)}}</span
+                >
+              </div>
+              <div class="info time shrink-0">
+                <span class="labels">鏃堕棿锛�</span>
+                <span class="text-content" style="font-size: 12px">
+                  {{ item.createtime }}</span
+                >
+              </div>
+            </div>
+            <div class="flex">
+              <div class="info">
+                <span class="labels">鎶ヨ鍐呭锛�</span>
+                <span
+                  class="text-content ciyao"
+                  :class="{ warning: item.alertdetail }"
+                >
+                  {{ item.alertdetail || "鏃�" }}</span
+                >
+              </div>
+            </div>
+          </div>
+        </li>
+      </ul>
+    </component>
   </div>
 </template>
 
-<style scoped lang='scss'>
+<style scoped lang="scss">
+.right_bottom {
+  width: 100%;
+  height: 100%;
 
-</style>
\ No newline at end of file
+  .right_center_item {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: auto;
+    padding: 10px;
+    font-size: 14px;
+    color: #fff;
+
+    .orderNum {
+      margin: 0 20px 0 -20px;
+    }
+
+    .inner_right {
+      position: relative;
+      height: 100%;
+      width: 400px;
+      flex-shrink: 0;
+      line-height: 1.5;
+
+      .dibu {
+        position: absolute;
+        height: 2px;
+        width: 104%;
+        background-image: url("@/assets/img/zuo_xuxian.png");
+        bottom: -12px;
+        left: -2%;
+        background-size: cover;
+      }
+    }
+
+    .info {
+      margin-right: 10px;
+      display: flex;
+      align-items: center;
+
+      .labels {
+        flex-shrink: 0;
+        font-size: 12px;
+        color: rgba(255, 255, 255, 0.6);
+      }
+
+      .zhuyao {
+        color: $primary-color;
+        font-size: 15px;
+      }
+
+      .ciyao {
+        color: rgba(255, 255, 255, 0.8);
+      }
+
+      .warning {
+        color: #e6a23c;
+        font-size: 15px;
+      }
+    }
+  }
+}
+
+.right_bottom_wrap {
+  overflow: hidden;
+  width: 100%;
+  height: 252px;
+}
+
+.overflow-y-auto {
+  overflow-y: auto;
+}
+</style>
diff --git a/src/views/setting.vue b/src/views/setting.vue
index 1302013..ca02c87 100644
--- a/src/views/setting.vue
+++ b/src/views/setting.vue
@@ -1,11 +1,20 @@
 <script setup lang="ts">
 import { useSettingStore } from "@/stores/index";
 import { ref } from "vue";
+import {storeToRefs} from "pinia"
 const isScaleRadio = ref(false);
+const leftBottomRadio=ref(true)
+const rightBottomRadio=ref(true)
 const settingStore = useSettingStore();
+const {indexConfig}=storeToRefs(settingStore)
+
 const init = () => {
   settingStore.initSetting();
   isScaleRadio.value = settingStore.isScale;
+
+  leftBottomRadio.value=indexConfig.value.leftBottomSwiper
+  rightBottomRadio.value=indexConfig.value.rightBottomSwiper
+
 };
 init();
 const handleClose = () => {};
@@ -18,11 +27,16 @@
 const isScaleChange = (flag: boolean) => {
   settingStore.setIsScale(flag);
 };
-const radiochange = (blag: boolean, type: string) => {
-  console.log(blag, type);
+const radiochange = (blag: boolean) => {
   settingStore.setIsScale(blag);
   // this.$store.commit('setting/updateSwiper', { val, type })
 };
+const indexRadioChange=(flag: boolean)=>{
+  settingStore.setIndexConfig({
+    leftBottomSwiper: leftBottomRadio.value,//宸﹁疆鎾�
+    rightBottomSwiper:rightBottomRadio.value,//鍙充笅杞挱
+  });
+}
 </script>
 
 <template>
@@ -45,6 +59,33 @@
           </el-radio-group>
         </div>
       </div>
+      <div class="left_shu">瀹炴椂鐩戞祴</div>
+      <div class="setting_item">
+        <span class="setting_label">
+          璁惧鎻愰啋鑷姩杞: <span class="setting_label_tip"></span>
+        </span>
+        <div class="setting_content">
+          <el-radio-group
+            v-model="leftBottomRadio"
+            @change="indexRadioChange"
+          >
+            <el-radio :label="true">鏄�</el-radio>
+            <el-radio :label="false">鍚�</el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+      <div class="setting_item">
+        <span class="setting_label"> 瀹炴椂棰勮杞挱: </span>
+        <div class="setting_content">
+          <el-radio-group
+            v-model="rightBottomRadio"
+            @change="indexRadioChange"
+          >
+            <el-radio :label="true">鏄�</el-radio>
+            <el-radio :label="false">鍚�</el-radio>
+          </el-radio-group>
+        </div>
+      </div>
     </template>
     <!-- <template #footer>
       <div style="flex: auto">
diff --git a/types/global.d.ts b/types/global.d.ts
index dbb4020..653a7de 100644
--- a/types/global.d.ts
+++ b/types/global.d.ts
@@ -1,3 +1,5 @@
 interface Window {
   $message: any
 }
+
+type TimeProp= NodeJS.Timeout
\ No newline at end of file

--
Gitblit v1.8.0