diff --git a/package.json b/package.json index 2684db72c7fecc8d4548900c63c8de218049b40c..e793bb013000667549fd4d5965e094342214aefe 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "axios": "^0.27.2", "core-js": "^3.6.5", "decimal.js": "^10.4.2", - "echarts": "^5.3.2", + "echarts": "^5.4.1", "lodash-es": "^4.17.21", "mitt": "^3.0.0", "pinia": "^2.0.14", diff --git a/src/modules/page10/config.ts b/src/modules/page10/config.ts index 6c4dc04d232795e0317d5d46512cca49500d24dc..63b0aace33ed6563e8d05c66cda7dda542e12a0a 100644 --- a/src/modules/page10/config.ts +++ b/src/modules/page10/config.ts @@ -1251,4 +1251,32 @@ export const poems = [ color: '#E7F6F2', }, }, + { + key: '126', + author: '柳永', + content: ['æ‰å佳人,自是白衣å¿ç›¸'], + style: { + backgroundImage: + 'linear-gradient(25deg, #0b6892, #6789af, #a5accd, #e2d0eb)', + color: '#ffffff', + }, + }, + { + key: '127', + author: 'æŽç™½', + content: ['事了拂衣去,深è—功与å'], + style: { + backgroundColor: '#615760', + color: '#DBAE21', + }, + }, + { + key: '128', + author: 'è‹è½¼', + content: ['麤(cū)缯大布裹生涯,腹有诗书气自åŽ'], + style: { + backgroundColor: '#6A5F5C', + color: '#E18689', + }, + }, ]; diff --git a/src/modules/page10/element/MyPoems.vue b/src/modules/page10/element/MyPoems.vue index 3588a41c78287fd0b8f4518466f080224cd55a8d..b8a4674cdd3a5ac33b3d8d9bc5741c9e59a2127f 100644 --- a/src/modules/page10/element/MyPoems.vue +++ b/src/modules/page10/element/MyPoems.vue @@ -27,10 +27,10 @@ const { info } = useMessage(); const source = ref(require('../media/羽肿-花ç«ãŒçž¬ã夜ã«.mp3')); const isPlaying = ref(false); const carouselRef = ref<any>(null); -const slide = ref('125'); +const slide = ref('128'); onMounted(() => { - rightClick(); + // rightClick(); }); function getStyle(data: any) { @@ -113,7 +113,7 @@ function onPlaying() { transition-prev="fade" transition-next="fade" :transition-duration="1500" - :autoplay="8000" + arrows animated infinite height="100%" @@ -274,19 +274,23 @@ function onPlaying() { .rotate-animate { animation: rotate 3s linear infinite; } -:deep(.my-media-player - .q-media__controls - .q-slider - .q-slider__track-container - .q-slider__track) { +:deep( + .my-media-player + .q-media__controls + .q-slider + .q-slider__track-container + .q-slider__track + ) { color: #306e8a; } -:deep(.my-media-player - .q-media__controls - .q-slider - .q-slider__track-container - .q-slider__track - .q-slider__thumb) { +:deep( + .my-media-player + .q-media__controls + .q-slider + .q-slider__track-container + .q-slider__track + .q-slider__thumb + ) { color: #306e8a; } </style> diff --git a/src/modules/vue-study/IndexPage.vue b/src/modules/vue-study/IndexPage.vue index d1364473144d4838845161caa0e6fc3d557ec601..4626555ace86cc7e9c7ac66da2c5038bd9aa4bd8 100644 --- a/src/modules/vue-study/IndexPage.vue +++ b/src/modules/vue-study/IndexPage.vue @@ -11,7 +11,9 @@ import { reactive, onMounted, watch, ref, nextTick, markRaw } from 'vue'; import * as echarts from 'echarts'; // import { useMessage } from 'src/common/hooks'; import PROVICE from './provice'; -import { ChartOption } from './config'; +import { ChartOption, Series_A, Series_B, Series_D } from './config'; +import DateDetail from './element/DateDetail.vue'; +import ImageScale from './element/ImageScale.vue'; // const { info } = useMessage(); @@ -20,6 +22,12 @@ const regionSelectRef = ref<any>(null); const chartRef = ref<any>(null); const showContent = ref(false); +const showContent2 = ref(false); +const legendState = reactive<any>({ + A: { show: true }, + B: { show: false }, + D: { show: true }, +}); const state = reactive({ province: null as any, provinceOpt: [] as any[], @@ -67,16 +75,43 @@ function handleData() { } function setChart() { - state.myChart = markRaw(echarts.init(chartRef.value)); - state.myChart.setOption(ChartOption); + let option: { series: any[] } = ChartOption; + let series = []; + + if (legendState.A.show) { + series.push(...Series_A); + } + if (legendState.B.show) { + series.push(...Series_B); + } + if (legendState.D.show) { + series.push(...Series_D); + } + option.series = series; + + if (state.myChart?.id) { + // state.myChart.dispose(); + state.myChart.setOption(option, true); + } else { + state.myChart = markRaw(echarts.init(chartRef.value)); + state.myChart.setOption(option); + } } function showBox() { showContent.value = !showContent.value; } +function showDate() { + showContent2.value = !showContent2.value; +} // function clickChartBox(e: any) { // e.stopPropagation(); // 阻æ¢å†’泡 // } + +function clickLegend(type: string) { + legendState[type].show = !legendState[type].show; + setChart(); +} </script> <template> <div> @@ -133,13 +168,76 @@ function showBox() { </div> </div> <div class="chart-box" ref="chartRef"></div> - <div class="legend-box"></div> + <div class="legend-box"> + <div + :class="[ + 'legend-box-item', + legendState.A.show ? 'opacity-1' : 'opacity-dis-4', + ]" + @click="clickLegend('A')" + > + <div class="legend-icon legend-icon-A"></div> + <div class="legend-title">A</div> + </div> + <div + :class="[ + 'legend-box-item', + legendState.B.show ? 'opacity-1' : 'opacity-dis-4', + ]" + @click="clickLegend('B')" + > + <div class="legend-icon legend-icon-B"></div> + <div class="legend-title">B/C</div> + </div> + <div + :class="[ + 'legend-box-item', + legendState.D.show ? 'opacity-1' : 'opacity-dis-4', + ]" + @click="clickLegend('D')" + > + <div class="legend-icon legend-icon-D"></div> + <div class="legend-title">D/E</div> + </div> + </div> </div> </div> + <div class="row"> + <div class="aniamte-box q-pa-md relative-position" style="width: 400px"> + <div + :class="['square', showContent2 ? 'square-show-date' : 'square-hide']" + > + <div class="title-box cursor-pointer" @click="showDate"> + <div class="title-text">日期</div> + <div class="title-action"> + <div + :class="[ + 'icon-box', + showContent2 ? 'icon-box-show' : 'icon-box-hide', + ]" + > + <q-icon name="expand_more" /> + </div> + </div> + </div> + <div class="chart-box" style="height: 620px"> + <DateDetail /> + </div> + </div> + </div> + + <ImageScale /> + </div> </div> </template> <style lang="scss" scoped> +.opacity-1 { + opacity: 1; +} +.opacity-dis-4 { + opacity: 0.4; +} .item-box { display: flex; column-gap: 16px; @@ -198,11 +296,68 @@ function showBox() { } .legend-box { position: absolute; - width: 130px; - height: 100px; - background-color: pink; + width: 80px; + // background-color: pink; top: 160px; right: 0; + .legend-box-item { + width: 100%; + box-sizing: border-box; + min-height: 24px; + // background-color: aqua; + display: flex; + align-items: center; + + &:hover { + cursor: pointer; + } + .legend-icon { + width: 28px; + height: 24px; + flex-shrink: 0; + // background-color: red; + position: relative; + margin-right: 8px; + &::before { + position: absolute; + content: ''; + width: 100%; + + top: 10px; + left: 0; + } + } + .legend-icon-A { + &::before { + border-top: 2px solid #f2317f; + } + &::after { + position: absolute; + content: ''; + width: 8px; + height: 8px; + border-radius: 50%; + border: 2px solid #f2317f; + background-color: #fff; + top: 7px; + left: 10px; + } + } + .legend-icon-B { + &::before { + border-top: 2px dashed #a696c8; + } + } + .legend-icon-D { + &::before { + border-top: 2px solid #8bc24c; + } + } + .legend-title { + font-size: 12px; + color: rgb(94, 94, 94); + } + } } } .square-hide { @@ -213,4 +368,8 @@ function showBox() { height: 340px; border-radius: 12px; } +.square-show-date { + height: 660px; + border-radius: 12px; +} </style> diff --git a/src/modules/vue-study/config.ts b/src/modules/vue-study/config.ts index f6de2692ff73dac420baa8de39c0522e8eb3c9d1..a2efdbcb7325dc23da5f1c1b1f27031a7365ed9d 100644 --- a/src/modules/vue-study/config.ts +++ b/src/modules/vue-study/config.ts @@ -7,12 +7,12 @@ export const ChartOption = { tooltip: { trigger: 'axis', }, - // legend: { - // data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine'], - // }, + // legend: { + // data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine'], + // }, grid: { left: 60, - right: 140, + right: 110, bottom: 40, top: 60, }, @@ -23,31 +23,64 @@ export const ChartOption = { yAxis: { type: 'value', }, - series: [ - { - name: 'Email', - type: 'line', - data: [120, 132, 101, 134, 90, 230, 210], + series: [], +}; + +export const Series_A = [ + { + name: 'A', + type: 'line', + data: [820, 932, 901, 934, 1290, 1330, 1320], + itemStyle: { + color: '#f2317f', }, - { - name: 'Union Ads', - type: 'line', - data: [220, 182, 191, 234, 290, 330, 310], + }, +]; +export const Series_B = [ + { + name: 'B', + type: 'line', + data: [150, 232, 201, 154, 190, 330, 410], + symbol: 'none', + itemStyle: { + color: '#a696c8', }, - { - name: 'Video Ads', - type: 'line', - data: [150, 232, 201, 154, 190, 330, 410], + lineStyle: { + type: 'dashed', //'dotted'点型虚线 'solid'实线 'dashed'线性虚线 }, - { - name: 'Direct', - type: 'line', - data: [320, 332, 301, 334, 390, 330, 320], + }, + { + name: 'C', + type: 'line', + data: [320, 332, 301, 334, 390, 330, 320], + symbol: 'none', + itemStyle: { + color: '#a696c8', }, - { - name: 'Search Engine', - type: 'line', - data: [820, 932, 901, 934, 1290, 1330, 1320], + lineStyle: { + type: 'dashed', }, - ], -}; + }, +]; +export const Series_D = [ + { + name: 'D', + type: 'line', + data: [220, 182, 191, 234, 290, 330, 310], + // 设置å°åœ†ç‚¹æ¶ˆå¤± + // 注æ„:设置symbol: 'none'以åŽï¼Œæ‹ç‚¹ä¸å˜åœ¨äº†ï¼Œè®¾ç½®æ‹ç‚¹ä¸Šæ˜¾ç¤ºæ•°å€¼æ— 效 + symbol: 'none', + itemStyle: { + color: '#8bc24c', + }, + }, + { + name: 'E', + type: 'line', + data: [120, 132, 101, 134, 90, 230, 210], + symbol: 'none', + itemStyle: { + color: '#8bc24c', + }, + }, +]; diff --git a/src/modules/vue-study/element/DateDetail.vue b/src/modules/vue-study/element/DateDetail.vue new file mode 100644 index 0000000000000000000000000000000000000000..c0f710f85c38a4cf611eb06b5d823bf3dd03115b --- /dev/null +++ b/src/modules/vue-study/element/DateDetail.vue @@ -0,0 +1,179 @@ +<script setup lang="ts"> +import { reactive } from 'vue'; + +const dateMsg = reactive({ + date: '2023-03-20', + week: '周一', + day: '20', + detail: [ + ['癸å¯(å…”)å¹´', '二月廿ä¹'], + ['ä¹™å¯(å…”)月', 'ä¸ä¸‘(牛)æ—¥'], + ['本年第12周', '第79天'], + ], + zodiac: 'å…”', + constellation: 'åŒé±¼åº§', + suitable: [ + 'ç¥ç¥€', + '订盟', + '纳采', + 'ä¿®é€ ', + '动土', + '祈ç¦', + '塑绘', + '斋醮', + 'æ²æµ´', + '拆å¸', + '起基', + '入宅', + '安香', + 'é€ åº™', + '移柩', + '谢土', + '除æœ', + 'æˆæœ', + 'å…¥å¦', + 'ä¹ è‰º', + '出行', + '竖柱', + '上æ¢', + '掘井', + '求嗣', + '解除', + '伿œ¨', + ], + taboo: ['作ç¶', '安葬', '开市', '盖屋'], + moon: '晓月', + phenology: 'é¹°åŒ–ä¸ºé¸ ', + good_direction: 'æ£å—', + sun_direction: '西北', + cloudy_direction: 'æ£è¥¿', + happy_direction: '东å—', + wealth_direction: '西å—', +}); +</script> +<template> + <div class="box"> + <div> + {{ dateMsg.date }} + + {{ dateMsg.week }} + </div> + <div class="day-box">{{ dateMsg.day }}</div> + <div class="detail-box"> + <div class="align-right">{{ dateMsg.detail[0][0] }}</div> + <div>{{ dateMsg.detail[0][1] }}</div> + <div class="align-right">{{ dateMsg.detail[1][0] }}</div> + <div>{{ dateMsg.detail[1][1] }}</div> + <div class="align-right">{{ dateMsg.detail[2][0] }}</div> + <div>{{ dateMsg.detail[2][1] }}</div> + </div> + <div class="line"></div> + <div class="middle-item"> + <div class="legend" style="background: #ffc300">生肖</div> + <div class="text-grey-6">{{ dateMsg.zodiac }}</div> + </div> + <div class="line"></div> + <div class="middle-item"> + <div class="legend" style="background: #02c9c9">星座</div> + <div class="text-grey-6">{{ dateMsg.constellation }}</div> + </div> + <div class="line"></div> + <div class="middle-item"> + <div class="legend" style="background: #bccf3d">宜</div> + <div class="text-grey-6">{{ dateMsg.suitable.join(',') }}</div> + </div> + <div class="line"></div> + <div class="middle-item"> + <div class="legend" style="background: #eb5651">忌</div> + <div class="text-grey-6">{{ dateMsg.taboo.join(',') }}</div> + </div> + <div class="line"></div> + <div class="row full-width"> + <div class="row col-6"> + <div class="legend" style="background: #c5bd99">月相</div> + <div class="text-grey-6">{{ dateMsg.moon }}</div> + </div> + <div class="row col-6"> + <div class="legend" style="background: #c5bd99">物候</div> + <div class="text-grey-6">{{ dateMsg.phenology }}</div> + </div> + </div> + <div class="line"></div> + <div class="full-width"> + <div class="text-grey-6">喜神方ä½ï¼š{{ dateMsg.good_direction }}</div> + <div class="text-grey-6">阳贵神方ä½ï¼š{{ dateMsg.sun_direction }}</div> + <div class="text-grey-6">阴贵方ä½ï¼š{{ dateMsg.cloudy_direction }}</div> + <div class="text-grey-6">ç¦ç¥žæ–¹ä½ï¼š{{ dateMsg.happy_direction }}</div> + <div class="text-grey-6">财神方ä½ï¼š{{ dateMsg.wealth_direction }}</div> + </div> + </div> +</template> + +<style lang="scss" scoped> +.box { + height: 100%; + overflow: auto; + display: flex; + flex-direction: column; + align-items: center; + padding: 14px; +} +.align-right { + text-align: right; +} +.line { + width: 100%; + height: 1px; + background-color: rgba(180, 180, 180, 0.3); +} +.legend { + color: #fff; + padding: 0 5px; + border-radius: 4px; + margin-right: 10px; + font-size: 13px; + flex: 0 0 auto; + align-self: flex-start; +} +.day-box { + width: 80px; + height: 80px; + margin: 8px 0; + color: #fff; + background-color: #e8a0b8; + border-radius: 10px; + font-size: 50px; + text-align: center; + line-height: 90px; + position: relative; + &::before { + position: absolute; + content: ''; + width: 6px; + height: 6px; + background-color: #fff; + border-radius: 50%; + top: 8px; + left: 8px; + } + &::after { + position: absolute; + content: ''; + width: 6px; + height: 6px; + background-color: #fff; + border-radius: 50%; + top: 8px; + right: 8px; + } +} +.detail-box { + display: grid; + grid-template-columns: 1fr 1fr; + column-gap: 10px; +} +.middle-item { + width: 100%; + display: flex; +} +</style> diff --git a/src/modules/vue-study/element/ImageScale.vue b/src/modules/vue-study/element/ImageScale.vue new file mode 100644 index 0000000000000000000000000000000000000000..a6a81ebc93762f6face953e291ac3b9d0a824f48 --- /dev/null +++ b/src/modules/vue-study/element/ImageScale.vue @@ -0,0 +1,131 @@ +<script setup lang="ts"> +import { ref, reactive } from 'vue'; + +const imgUrl = ref('https://w.wallhaven.cc/full/kx/wallhaven-kx98xd.jpg'); +const standard = ref(100); +const state = reactive({ + zoomVal: 1, + left: 0, + top: 0, +}); + +function onMousedown(e: any) { + let oDiv = e.target; // 获å–当å‰å…ƒç´ + // ç®—å‡ºé¼ æ ‡ç›¸å¯¹å…ƒç´ çš„ä½ç½® + let disX = e.clientX - oDiv.offsetLeft; + let disY = e.clientY - oDiv.offsetTop; + + document.onmousemove = function (e: any) { + // ç”¨é¼ æ ‡çš„ä½ç½®å‡åŽ»é¼ æ ‡ç›¸å¯¹å…ƒç´ çš„ä½ç½®ï¼Œå¾—åˆ°å…ƒç´ çš„ä½ç½® + let left = e.clientX - disX; + let top = e.clientY - disY; + // oDiv.style.left = left + 'px'; + // oDiv.style.top = top + 'px'; + state.left = left; + state.top = top; + }; + + //为documentç»‘å®šä¸€ä¸ªé¼ æ ‡æŠ¬èµ·äº‹ä»¶ï¼Œé¼ æ ‡æ¾å¼€æ—¶ï¼Œå°†box固定在当å‰ä½ç½® + document.onmouseup = function () { + //å–æ¶ˆdocumentçš„onmousemove事件 + document.onmousemove = null; + + //å–æ¶ˆdocumentçš„onmouseup事件 + document.onmouseup = null; + }; +} +function onWheel(e: any) { + let direction = e.deltaY > 0 ? 'down' : 'up'; + let val = state.zoomVal; + if (direction === 'up') { + // 滑轮å‘上滚动 + val += 0.1; + if (val >= 2) { + val = 2; + } + } else { + // 滑轮å‘下滚动 + val -= 0.1; + if (val <= 0.2) { + val = 0.2; + } + } + + let diffScale = val - state.zoomVal; + let diffX = e.offsetX * diffScale; + let diffY = e.offsetY * diffScale; + + state.zoomVal = val; + standard.value = Number((val * 100).toFixed(2)); + state.left -= diffX; + state.top -= diffY; +} +function sliderUpdate(value: any) { + state.zoomVal = value / 100; +} +</script> +<template> + <div class="box q-ma-md"> + <div class="tool-box"> + <q-slider + v-model="standard" + :inner-min="20" + :min="0" + :max="200" + label + :label-value="standard + '%'" + @update:model-value="sliderUpdate" + /> + </div> + <div class="img-box"> + <div + class="img-mask" + @mousedown.prevent="onMousedown" + @mousewheel.prevent="onWheel" + :style="{ + backgroundImage: `url(${imgUrl})`, + transform: `scale(${state.zoomVal})`, + left: state.left + 'px', + top: state.top + 'px', + }" + ></div> + </div> + </div> +</template> + +<style lang="scss" scoped> +.box { + width: 800px; + height: 500px; +} +.tool-box { + box-sizing: border-box; + height: 40px; + border-top: 1px solid rgba(180, 180, 180, 0.3); + border-left: 1px solid rgba(180, 180, 180, 0.3); + border-right: 1px solid rgba(180, 180, 180, 0.3); + display: flex; + align-items: center; + padding: 0 16px; +} +.img-box { + height: calc(500px - 40px); + width: 100%; + border: 1px solid rgba(180, 180, 180, 0.3); + overflow: hidden; + position: relative; + .img-mask { + position: absolute; + box-sizing: border-box; + background-color: pink; + width: 100%; + height: 100%; + top: 0; + left: 0; + transform-origin: 0 0; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } +} +</style> diff --git a/yarn.lock b/yarn.lock index 1fa3db3cc1140d5078ed0bf804e2bfdbd0bc38fb..9f82658e09d23257a2fa3a938e16e41b32dbd322 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2907,7 +2907,7 @@ duplexer@^0.1.2: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -echarts@^5.3.2: +echarts@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.4.1.tgz#d7f65a584d78beff62568d878b16151b3381811c" integrity sha512-9ltS3M2JB0w2EhcYjCdmtrJ+6haZcW6acBolMGIuf01Hql1yrIV01L1aRj7jsaaIULJslEP9Z3vKlEmnJaWJVQ==