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