diff --git a/src/components/ReFlicker/index.css b/src/components/ReFlicker/index.css new file mode 100644 index 0000000..4c40af4 --- /dev/null +++ b/src/components/ReFlicker/index.css @@ -0,0 +1,39 @@ +.point { + width: var(--point-width); + height: var(--point-height); + background: var(--point-background); + position: relative; + border-radius: var(--point-border-radius); +} + +.point-flicker:after { + background: var(--point-background); +} + +.point-flicker:before, +.point-flicker:after { + content: ""; + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + border-radius: var(--point-border-radius); + animation: flicker 1.2s ease-out infinite; +} + +@keyframes flicker { + 0% { + transform: scale(0.5); + opacity: 1; + } + + 30% { + opacity: 1; + } + + 100% { + transform: scale(var(--point-scale)); + opacity: 0; + } +} diff --git a/src/components/ReFlicker/index.ts b/src/components/ReFlicker/index.ts new file mode 100644 index 0000000..b829323 --- /dev/null +++ b/src/components/ReFlicker/index.ts @@ -0,0 +1,44 @@ +import "./index.css"; +import { type Component, h, defineComponent } from "vue"; + +export interface attrsType { + width?: string; + height?: string; + borderRadius?: number | string; + background?: string; + scale?: number | string; +} + +/** + * 圆点、方形闪烁动画组件 + * @param width 可选 string 宽 + * @param height 可选 string 高 + * @param borderRadius 可选 number | string 传0为方形、传50%或者不传为圆形 + * @param background 可选 string 闪烁颜色 + * @param scale 可选 number | string 闪烁范围,默认2,值越大闪烁范围越大 + * @returns Component + */ +export function useRenderFlicker(attrs?: attrsType): Component { + return defineComponent({ + name: "ReFlicker", + render() { + return h( + "div", + { + class: "point point-flicker", + style: { + "--point-width": attrs?.width ?? "12px", + "--point-height": attrs?.height ?? "12px", + "--point-background": + attrs?.background ?? "var(--el-color-primary)", + "--point-border-radius": attrs?.borderRadius ?? "50%", + "--point-scale": attrs?.scale ?? "2" + } + }, + { + default: () => [] + } + ); + } + }); +} diff --git a/src/main.ts b/src/main.ts index d0f733c..5237cdd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,13 +4,13 @@ import { setupStore } from "@/store"; import { useI18n } from "@/plugins/i18n"; import { getPlatformConfig } from "./config"; import { MotionPlugin } from "@vueuse/motion"; -// import { useEcharts } from "@/plugins/echarts"; +import { useEcharts } from "@/plugins/echarts"; import { createApp, type Directive } from "vue"; import { useElementPlus } from "@/plugins/elementPlus"; import { injectResponsiveStorage } from "@/utils/responsive"; import Table from "@pureadmin/table"; -// import PureDescriptions from "@pureadmin/descriptions"; +import PureDescriptions from "@pureadmin/descriptions"; // 引入重置样式 import "./style/reset.scss"; @@ -56,8 +56,12 @@ getPlatformConfig(app).then(async config => { app.use(router); await router.isReady(); injectResponsiveStorage(app, config); - app.use(MotionPlugin).use(useI18n).use(useElementPlus).use(Table); - // .use(PureDescriptions) - // .use(useEcharts); + app + .use(MotionPlugin) + .use(useI18n) + .use(useElementPlus) + .use(Table) + .use(PureDescriptions) + .use(useEcharts); app.mount("#app"); }); diff --git a/src/views/login/index.vue b/src/views/login/index.vue index d00579b..1b4a9cd 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -10,6 +10,8 @@ import { useNav } from "@/layout/hooks/useNav"; import { useEventListener } from "@vueuse/core"; import type { FormInstance } from "element-plus"; import { $t, transformI18n } from "@/plugins/i18n"; +import { getConfig } from "@/config"; + // import { operates } from "./utils/enums"; import { useLayout } from "@/layout/hooks/useLayout"; import LoginPhone from "./components/LoginPhone.vue"; @@ -34,6 +36,7 @@ import Info from "@iconify-icons/ri/information-line"; import { GetCaptchaAPI } from "@/api/login"; import { getUserInfoAPI } from "@/api/login"; import { setUserInfo } from "@/utils/auth"; +const Period = getConfig("Period"); defineOptions({ name: "Login" @@ -347,12 +350,8 @@ onMounted(async () => {
- Copyright © 2020-present - + Copyright © {{ Period }} +  {{ title }}
diff --git a/src/views/welcome/components/ChartBar.vue b/src/views/welcome/components/ChartBar.vue new file mode 100644 index 0000000..1983fd7 --- /dev/null +++ b/src/views/welcome/components/ChartBar.vue @@ -0,0 +1,108 @@ + + + diff --git a/src/views/welcome/index.vue b/src/views/welcome/index.vue index 3e4fb06..1a80c6e 100644 --- a/src/views/welcome/index.vue +++ b/src/views/welcome/index.vue @@ -2,8 +2,346 @@ defineOptions({ name: "Welcome" }); +import { ref, markRaw } from "vue"; +import dayjs from "dayjs"; +import ReCol from "@/components/ReCol"; +import ChartBar from "./components/ChartBar.vue"; +import { useRenderFlicker } from "@/components/ReFlicker"; +import Segmented, { type OptionsType } from "@/components/ReSegmented"; +import { useDark, cloneDeep, randomGradient } from "@pureadmin/utils"; + +import GroupLine from "@iconify-icons/ri/group-line"; +import Question from "@iconify-icons/ri/question-answer-line"; +import CheckLine from "@iconify-icons/ri/chat-check-line"; +import Smile from "@iconify-icons/ri/star-smile-line"; +const { isDark } = useDark(); +const getRandomIntBetween = (min: number, max: number) => { + return Math.floor(Math.random() * (max - min + 1)) + min; +}; +let curWeek = ref(1); // 0上周、1本周 +const optionsBasis: Array = [ + { + label: "上周" + }, + { + label: "本周" + } +]; +const days = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]; + +/** 需求人数、提问数量、解决数量、用户满意度 */ +const chartData = [ + { + icon: GroupLine, + bgColor: "#effaff", + color: "#41b6ff", + duration: 2200, + name: "需求人数", + value: 36000, + percent: "+88%", + data: [2101, 5288, 4239, 4962, 6752, 5208, 7450] // 平滑折线图数据 + }, + { + icon: Question, + bgColor: "#fff5f4", + color: "#e85f33", + duration: 1600, + name: "提问数量", + value: 16580, + percent: "+70%", + data: [2216, 1148, 1255, 788, 4821, 1973, 4379] + }, + { + icon: CheckLine, + bgColor: "#eff8f4", + color: "#26ce83", + duration: 1500, + name: "解决数量", + value: 16499, + percent: "+99%", + data: [861, 1002, 3195, 1715, 3666, 2415, 3645] + }, + { + icon: Smile, + bgColor: "#f6f4fe", + color: "#7846e5", + duration: 100, + name: "用户满意度", + value: 100, + percent: "+100%", + data: [100] + } +]; + +/** 分析概览 */ +const barChartData = [ + { + requireData: [2101, 5288, 4239, 4962, 6752, 5208, 7450], + questionData: [2216, 1148, 1255, 1788, 4821, 1973, 4379] + }, + { + requireData: [2101, 3280, 4400, 4962, 5752, 6889, 7600], + questionData: [2116, 3148, 3255, 3788, 4821, 4970, 5390] + } +]; +/** 数据统计 */ +const tableData = Array.from({ length: 30 }).map((_, index) => { + return { + id: index + 1, + requiredNumber: getRandomIntBetween(13500, 19999), + questionNumber: getRandomIntBetween(12600, 16999), + resolveNumber: getRandomIntBetween(13500, 17999), + satisfaction: getRandomIntBetween(95, 100), + date: dayjs().subtract(index, "day").format("YYYY-MM-DD") + }; +}); +/** 最新动态 */ +const latestNewsData = cloneDeep(tableData) + .slice(0, 14) + .map((item, index) => { + return Object.assign(item, { + date: `${dayjs().subtract(index, "day").format("YYYY-MM-DD")} ${ + days[dayjs().subtract(index, "day").day()] + }` + }); + }); + +