Commit 83954241aedf86005c3f25eae8ff5a57421fe516
1 parent
1e65b221
style: 切换页面布局
Showing
11 changed files
with
600 additions
and
602 deletions
yudao-ui-admin-vue3/src/views/Error/403.vue
| 1 | +<template> | ||
| 2 | + <Error type="403" @error-click="errorClick" /> | ||
| 3 | +</template> | ||
| 1 | <script setup lang="ts"> | 4 | <script setup lang="ts"> |
| 2 | import { Error } from '@/components/Error' | 5 | import { Error } from '@/components/Error' |
| 3 | import { useRouter } from 'vue-router' | 6 | import { useRouter } from 'vue-router' |
| @@ -8,7 +11,3 @@ const errorClick = () => { | @@ -8,7 +11,3 @@ const errorClick = () => { | ||
| 8 | push('/') | 11 | push('/') |
| 9 | } | 12 | } |
| 10 | </script> | 13 | </script> |
| 11 | - | ||
| 12 | -<template> | ||
| 13 | - <Error type="403" @error-click="errorClick" /> | ||
| 14 | -</template> |
yudao-ui-admin-vue3/src/views/Error/404.vue
| 1 | +<template> | ||
| 2 | + <Error @error-click="errorClick" /> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 1 | <script setup lang="ts"> | 5 | <script setup lang="ts"> |
| 2 | import { Error } from '@/components/Error' | 6 | import { Error } from '@/components/Error' |
| 3 | import { useRouter } from 'vue-router' | 7 | import { useRouter } from 'vue-router' |
| @@ -8,7 +12,3 @@ const errorClick = () => { | @@ -8,7 +12,3 @@ const errorClick = () => { | ||
| 8 | push('/') | 12 | push('/') |
| 9 | } | 13 | } |
| 10 | </script> | 14 | </script> |
| 11 | - | ||
| 12 | -<template> | ||
| 13 | - <Error @error-click="errorClick" /> | ||
| 14 | -</template> |
yudao-ui-admin-vue3/src/views/Error/500.vue
| 1 | +<template> | ||
| 2 | + <Error type="500" @error-click="errorClick" /> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 1 | <script setup lang="ts"> | 5 | <script setup lang="ts"> |
| 2 | import { Error } from '@/components/Error' | 6 | import { Error } from '@/components/Error' |
| 3 | import { useRouter } from 'vue-router' | 7 | import { useRouter } from 'vue-router' |
| @@ -8,7 +12,3 @@ const errorClick = () => { | @@ -8,7 +12,3 @@ const errorClick = () => { | ||
| 8 | push('/') | 12 | push('/') |
| 9 | } | 13 | } |
| 10 | </script> | 14 | </script> |
| 11 | - | ||
| 12 | -<template> | ||
| 13 | - <Error type="500" @error-click="errorClick" /> | ||
| 14 | -</template> |
yudao-ui-admin-vue3/src/views/Home/Index.vue
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <el-card shadow="never"> | ||
| 4 | + <el-skeleton :loading="loading" animated> | ||
| 5 | + <el-row :gutter="20" justify="space-between"> | ||
| 6 | + <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> | ||
| 7 | + <div class="flex items-center"> | ||
| 8 | + <img :src="avatar" alt="" class="w-70px h-70px rounded-[50%] mr-20px" /> | ||
| 9 | + <div> | ||
| 10 | + <div class="text-20px text-700"> | ||
| 11 | + {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }} | ||
| 12 | + </div> | ||
| 13 | + <div class="mt-10px text-14px text-gray-500"> | ||
| 14 | + {{ t('workplace.toady') }},20℃ - 32℃! | ||
| 15 | + </div> | ||
| 16 | + </div> | ||
| 17 | + </div> | ||
| 18 | + </el-col> | ||
| 19 | + <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> | ||
| 20 | + <div class="flex h-70px items-center justify-end <sm:mt-10px"> | ||
| 21 | + <div class="px-8px text-right"> | ||
| 22 | + <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.project') }}</div> | ||
| 23 | + <CountTo | ||
| 24 | + class="text-20px" | ||
| 25 | + :start-val="0" | ||
| 26 | + :end-val="totalSate.project" | ||
| 27 | + :duration="2600" | ||
| 28 | + /> | ||
| 29 | + </div> | ||
| 30 | + <el-divider direction="vertical" /> | ||
| 31 | + <div class="px-8px text-right"> | ||
| 32 | + <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.toDo') }}</div> | ||
| 33 | + <CountTo | ||
| 34 | + class="text-20px" | ||
| 35 | + :start-val="0" | ||
| 36 | + :end-val="totalSate.todo" | ||
| 37 | + :duration="2600" | ||
| 38 | + /> | ||
| 39 | + </div> | ||
| 40 | + <el-divider direction="vertical" border-style="dashed" /> | ||
| 41 | + <div class="px-8px text-right"> | ||
| 42 | + <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.access') }}</div> | ||
| 43 | + <CountTo | ||
| 44 | + class="text-20px" | ||
| 45 | + :start-val="0" | ||
| 46 | + :end-val="totalSate.access" | ||
| 47 | + :duration="2600" | ||
| 48 | + /> | ||
| 49 | + </div> | ||
| 50 | + </div> | ||
| 51 | + </el-col> | ||
| 52 | + </el-row> | ||
| 53 | + </el-skeleton> | ||
| 54 | + </el-card> | ||
| 55 | + </div> | ||
| 56 | + | ||
| 57 | + <el-row class="mt-5px" :gutter="20" justify="space-between"> | ||
| 58 | + <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-10px"> | ||
| 59 | + <el-card shadow="never"> | ||
| 60 | + <template #header> | ||
| 61 | + <div class="flex justify-between h-3"> | ||
| 62 | + <span>{{ t('workplace.project') }}</span> | ||
| 63 | + <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link> | ||
| 64 | + </div> | ||
| 65 | + </template> | ||
| 66 | + <el-skeleton :loading="loading" animated> | ||
| 67 | + <el-row> | ||
| 68 | + <el-col | ||
| 69 | + v-for="(item, index) in projects" | ||
| 70 | + :key="`card-${index}`" | ||
| 71 | + :xl="8" | ||
| 72 | + :lg="8" | ||
| 73 | + :md="8" | ||
| 74 | + :sm="24" | ||
| 75 | + :xs="24" | ||
| 76 | + > | ||
| 77 | + <el-card shadow="hover"> | ||
| 78 | + <div class="flex items-center"> | ||
| 79 | + <Icon :icon="item.icon" :size="25" class="mr-10px" /> | ||
| 80 | + <span class="text-16px">{{ item.name }}</span> | ||
| 81 | + </div> | ||
| 82 | + <div class="mt-15px text-14px text-gray-400">{{ t(item.message) }}</div> | ||
| 83 | + <div class="mt-20px text-12px text-gray-400 flex justify-between"> | ||
| 84 | + <span>{{ item.personal }}</span> | ||
| 85 | + <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span> | ||
| 86 | + </div> | ||
| 87 | + </el-card> | ||
| 88 | + </el-col> | ||
| 89 | + </el-row> | ||
| 90 | + </el-skeleton> | ||
| 91 | + </el-card> | ||
| 92 | + | ||
| 93 | + <el-card shadow="never" class="mt-5px"> | ||
| 94 | + <el-skeleton :loading="loading" animated> | ||
| 95 | + <el-row :gutter="20" justify="space-between"> | ||
| 96 | + <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24"> | ||
| 97 | + <el-card shadow="hover" class="mb-10px"> | ||
| 98 | + <el-skeleton :loading="loading" animated> | ||
| 99 | + <Echart :options="pieOptionsData" :height="280" /> | ||
| 100 | + </el-skeleton> | ||
| 101 | + </el-card> | ||
| 102 | + </el-col> | ||
| 103 | + <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24"> | ||
| 104 | + <el-card shadow="hover" class="mb-10px"> | ||
| 105 | + <el-skeleton :loading="loading" animated> | ||
| 106 | + <Echart :options="barOptionsData" :height="280" /> | ||
| 107 | + </el-skeleton> | ||
| 108 | + </el-card> | ||
| 109 | + </el-col> | ||
| 110 | + </el-row> | ||
| 111 | + </el-skeleton> | ||
| 112 | + </el-card> | ||
| 113 | + </el-col> | ||
| 114 | + <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-10px"> | ||
| 115 | + <el-card shadow="never"> | ||
| 116 | + <template #header> | ||
| 117 | + <div class="flex justify-between h-3"> | ||
| 118 | + <span>{{ t('workplace.shortcutOperation') }}</span> | ||
| 119 | + </div> | ||
| 120 | + </template> | ||
| 121 | + <el-skeleton :loading="loading" animated> | ||
| 122 | + <el-row> | ||
| 123 | + <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-10px"> | ||
| 124 | + <div class="flex items-center"> | ||
| 125 | + <Icon :icon="item.icon" class="mr-10px" /> | ||
| 126 | + <el-link type="default" :underline="false" :href="item.url"> | ||
| 127 | + {{ item.name }} | ||
| 128 | + </el-link> | ||
| 129 | + </div> | ||
| 130 | + </el-col> | ||
| 131 | + </el-row> | ||
| 132 | + </el-skeleton> | ||
| 133 | + </el-card> | ||
| 134 | + <el-card shadow="never" class="mt-10px"> | ||
| 135 | + <template #header> | ||
| 136 | + <div class="flex justify-between h-3"> | ||
| 137 | + <span>{{ t('workplace.notice') }}</span> | ||
| 138 | + <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link> | ||
| 139 | + </div> | ||
| 140 | + </template> | ||
| 141 | + <el-skeleton :loading="loading" animated> | ||
| 142 | + <div v-for="(item, index) in notice" :key="`dynamics-${index}`"> | ||
| 143 | + <div class="flex items-center"> | ||
| 144 | + <img :src="avatar" alt="" class="w-35px h-35px rounded-[50%] mr-20px" /> | ||
| 145 | + <div> | ||
| 146 | + <div class="text-14px"> | ||
| 147 | + <Highlight :keys="item.keys.map((v) => t(v))"> | ||
| 148 | + {{ item.type }} : {{ item.title }} | ||
| 149 | + </Highlight> | ||
| 150 | + </div> | ||
| 151 | + <div class="mt-15px text-12px text-gray-400"> | ||
| 152 | + {{ formatTime(item.date, 'yyyy-MM-dd') }} | ||
| 153 | + </div> | ||
| 154 | + </div> | ||
| 155 | + </div> | ||
| 156 | + <el-divider /> | ||
| 157 | + </div> | ||
| 158 | + </el-skeleton> | ||
| 159 | + </el-card> | ||
| 160 | + </el-col> | ||
| 161 | + </el-row> | ||
| 162 | +</template> | ||
| 1 | <script setup lang="ts"> | 163 | <script setup lang="ts"> |
| 2 | import { ElRow, ElCol, ElSkeleton, ElCard, ElDivider, ElLink } from 'element-plus' | 164 | import { ElRow, ElCol, ElSkeleton, ElCard, ElDivider, ElLink } from 'element-plus' |
| 3 | import { useI18n } from '@/hooks/web/useI18n' | 165 | import { useI18n } from '@/hooks/web/useI18n' |
| @@ -217,166 +379,3 @@ const getAllApi = async () => { | @@ -217,166 +379,3 @@ const getAllApi = async () => { | ||
| 217 | 379 | ||
| 218 | getAllApi() | 380 | getAllApi() |
| 219 | </script> | 381 | </script> |
| 220 | - | ||
| 221 | -<template> | ||
| 222 | - <div> | ||
| 223 | - <el-card shadow="never"> | ||
| 224 | - <el-skeleton :loading="loading" animated> | ||
| 225 | - <el-row :gutter="20" justify="space-between"> | ||
| 226 | - <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> | ||
| 227 | - <div class="flex items-center"> | ||
| 228 | - <img :src="avatar" alt="" class="w-70px h-70px rounded-[50%] mr-20px" /> | ||
| 229 | - <div> | ||
| 230 | - <div class="text-20px text-700"> | ||
| 231 | - {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }} | ||
| 232 | - </div> | ||
| 233 | - <div class="mt-10px text-14px text-gray-500"> | ||
| 234 | - {{ t('workplace.toady') }},20℃ - 32℃! | ||
| 235 | - </div> | ||
| 236 | - </div> | ||
| 237 | - </div> | ||
| 238 | - </el-col> | ||
| 239 | - <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> | ||
| 240 | - <div class="flex h-70px items-center justify-end <sm:mt-10px"> | ||
| 241 | - <div class="px-8px text-right"> | ||
| 242 | - <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.project') }}</div> | ||
| 243 | - <CountTo | ||
| 244 | - class="text-20px" | ||
| 245 | - :start-val="0" | ||
| 246 | - :end-val="totalSate.project" | ||
| 247 | - :duration="2600" | ||
| 248 | - /> | ||
| 249 | - </div> | ||
| 250 | - <el-divider direction="vertical" /> | ||
| 251 | - <div class="px-8px text-right"> | ||
| 252 | - <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.toDo') }}</div> | ||
| 253 | - <CountTo | ||
| 254 | - class="text-20px" | ||
| 255 | - :start-val="0" | ||
| 256 | - :end-val="totalSate.todo" | ||
| 257 | - :duration="2600" | ||
| 258 | - /> | ||
| 259 | - </div> | ||
| 260 | - <el-divider direction="vertical" border-style="dashed" /> | ||
| 261 | - <div class="px-8px text-right"> | ||
| 262 | - <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.access') }}</div> | ||
| 263 | - <CountTo | ||
| 264 | - class="text-20px" | ||
| 265 | - :start-val="0" | ||
| 266 | - :end-val="totalSate.access" | ||
| 267 | - :duration="2600" | ||
| 268 | - /> | ||
| 269 | - </div> | ||
| 270 | - </div> | ||
| 271 | - </el-col> | ||
| 272 | - </el-row> | ||
| 273 | - </el-skeleton> | ||
| 274 | - </el-card> | ||
| 275 | - </div> | ||
| 276 | - | ||
| 277 | - <el-row class="mt-5px" :gutter="20" justify="space-between"> | ||
| 278 | - <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-10px"> | ||
| 279 | - <el-card shadow="never"> | ||
| 280 | - <template #header> | ||
| 281 | - <div class="flex justify-between h-3"> | ||
| 282 | - <span>{{ t('workplace.project') }}</span> | ||
| 283 | - <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link> | ||
| 284 | - </div> | ||
| 285 | - </template> | ||
| 286 | - <el-skeleton :loading="loading" animated> | ||
| 287 | - <el-row> | ||
| 288 | - <el-col | ||
| 289 | - v-for="(item, index) in projects" | ||
| 290 | - :key="`card-${index}`" | ||
| 291 | - :xl="8" | ||
| 292 | - :lg="8" | ||
| 293 | - :md="8" | ||
| 294 | - :sm="24" | ||
| 295 | - :xs="24" | ||
| 296 | - > | ||
| 297 | - <el-card shadow="hover"> | ||
| 298 | - <div class="flex items-center"> | ||
| 299 | - <Icon :icon="item.icon" :size="25" class="mr-10px" /> | ||
| 300 | - <span class="text-16px">{{ item.name }}</span> | ||
| 301 | - </div> | ||
| 302 | - <div class="mt-15px text-14px text-gray-400">{{ t(item.message) }}</div> | ||
| 303 | - <div class="mt-20px text-12px text-gray-400 flex justify-between"> | ||
| 304 | - <span>{{ item.personal }}</span> | ||
| 305 | - <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span> | ||
| 306 | - </div> | ||
| 307 | - </el-card> | ||
| 308 | - </el-col> | ||
| 309 | - </el-row> | ||
| 310 | - </el-skeleton> | ||
| 311 | - </el-card> | ||
| 312 | - | ||
| 313 | - <el-card shadow="never" class="mt-5px"> | ||
| 314 | - <el-skeleton :loading="loading" animated> | ||
| 315 | - <el-row :gutter="20" justify="space-between"> | ||
| 316 | - <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24"> | ||
| 317 | - <el-card shadow="hover" class="mb-10px"> | ||
| 318 | - <el-skeleton :loading="loading" animated> | ||
| 319 | - <Echart :options="pieOptionsData" :height="280" /> | ||
| 320 | - </el-skeleton> | ||
| 321 | - </el-card> | ||
| 322 | - </el-col> | ||
| 323 | - <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24"> | ||
| 324 | - <el-card shadow="hover" class="mb-10px"> | ||
| 325 | - <el-skeleton :loading="loading" animated> | ||
| 326 | - <Echart :options="barOptionsData" :height="280" /> | ||
| 327 | - </el-skeleton> | ||
| 328 | - </el-card> | ||
| 329 | - </el-col> | ||
| 330 | - </el-row> | ||
| 331 | - </el-skeleton> | ||
| 332 | - </el-card> | ||
| 333 | - </el-col> | ||
| 334 | - <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-10px"> | ||
| 335 | - <el-card shadow="never"> | ||
| 336 | - <template #header> | ||
| 337 | - <div class="flex justify-between h-3"> | ||
| 338 | - <span>{{ t('workplace.shortcutOperation') }}</span> | ||
| 339 | - </div> | ||
| 340 | - </template> | ||
| 341 | - <el-skeleton :loading="loading" animated> | ||
| 342 | - <el-row> | ||
| 343 | - <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-10px"> | ||
| 344 | - <div class="flex items-center"> | ||
| 345 | - <Icon :icon="item.icon" class="mr-10px" /> | ||
| 346 | - <el-link type="default" :underline="false" :href="item.url"> | ||
| 347 | - {{ item.name }} | ||
| 348 | - </el-link> | ||
| 349 | - </div> | ||
| 350 | - </el-col> | ||
| 351 | - </el-row> | ||
| 352 | - </el-skeleton> | ||
| 353 | - </el-card> | ||
| 354 | - <el-card shadow="never" class="mt-10px"> | ||
| 355 | - <template #header> | ||
| 356 | - <div class="flex justify-between h-3"> | ||
| 357 | - <span>{{ t('workplace.notice') }}</span> | ||
| 358 | - <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link> | ||
| 359 | - </div> | ||
| 360 | - </template> | ||
| 361 | - <el-skeleton :loading="loading" animated> | ||
| 362 | - <div v-for="(item, index) in notice" :key="`dynamics-${index}`"> | ||
| 363 | - <div class="flex items-center"> | ||
| 364 | - <img :src="avatar" alt="" class="w-35px h-35px rounded-[50%] mr-20px" /> | ||
| 365 | - <div> | ||
| 366 | - <div class="text-14px"> | ||
| 367 | - <Highlight :keys="item.keys.map((v) => t(v))"> | ||
| 368 | - {{ item.type }} : {{ item.title }} | ||
| 369 | - </Highlight> | ||
| 370 | - </div> | ||
| 371 | - <div class="mt-15px text-12px text-gray-400"> | ||
| 372 | - {{ formatTime(item.date, 'yyyy-MM-dd') }} | ||
| 373 | - </div> | ||
| 374 | - </div> | ||
| 375 | - </div> | ||
| 376 | - <el-divider /> | ||
| 377 | - </div> | ||
| 378 | - </el-skeleton> | ||
| 379 | - </el-card> | ||
| 380 | - </el-col> | ||
| 381 | - </el-row> | ||
| 382 | -</template> |
yudao-ui-admin-vue3/src/views/Home/Index2.vue
| 1 | -<script setup lang="ts"> | ||
| 2 | -import { ref, reactive } from 'vue' | ||
| 3 | -import { set } from 'lodash-es' | ||
| 4 | -import { EChartsOption } from 'echarts' | ||
| 5 | -import { Echart } from '@/components/Echart' | ||
| 6 | -import { useI18n } from '@/hooks/web/useI18n' | ||
| 7 | -import { CountTo } from '@/components/CountTo' | ||
| 8 | -import type { AnalysisTotalTypes } from './types' | ||
| 9 | -import { useDesign } from '@/hooks/web/useDesign' | ||
| 10 | -import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus' | ||
| 11 | -import { pieOptions, barOptions, lineOptions } from './echarts-data' | ||
| 12 | - | ||
| 13 | -const { t } = useI18n() | ||
| 14 | -const loading = ref(true) | ||
| 15 | -const { getPrefixCls } = useDesign() | ||
| 16 | -const prefixCls = getPrefixCls('panel') | ||
| 17 | -const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption | ||
| 18 | - | ||
| 19 | -let totalState = reactive<AnalysisTotalTypes>({ | ||
| 20 | - users: 0, | ||
| 21 | - messages: 0, | ||
| 22 | - moneys: 0, | ||
| 23 | - shoppings: 0 | ||
| 24 | -}) | ||
| 25 | - | ||
| 26 | -const getCount = async () => { | ||
| 27 | - const data = { | ||
| 28 | - users: 102400, | ||
| 29 | - messages: 81212, | ||
| 30 | - moneys: 9280, | ||
| 31 | - shoppings: 13600 | ||
| 32 | - } | ||
| 33 | - totalState = Object.assign(totalState, data) | ||
| 34 | -} | ||
| 35 | - | ||
| 36 | -// 用户来源 | ||
| 37 | -const getUserAccessSource = async () => { | ||
| 38 | - const data = [ | ||
| 39 | - { value: 335, name: 'analysis.directAccess' }, | ||
| 40 | - { value: 310, name: 'analysis.mailMarketing' }, | ||
| 41 | - { value: 234, name: 'analysis.allianceAdvertising' }, | ||
| 42 | - { value: 135, name: 'analysis.videoAdvertising' }, | ||
| 43 | - { value: 1548, name: 'analysis.searchEngines' } | ||
| 44 | - ] | ||
| 45 | - set( | ||
| 46 | - pieOptionsData, | ||
| 47 | - 'legend.data', | ||
| 48 | - data.map((v) => t(v.name)) | ||
| 49 | - ) | ||
| 50 | - set(pieOptionsData, 'series.data', data) | ||
| 51 | -} | ||
| 52 | -const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption | ||
| 53 | - | ||
| 54 | -// 周活跃量 | ||
| 55 | -const getWeeklyUserActivity = async () => { | ||
| 56 | - const data = [ | ||
| 57 | - { value: 13253, name: 'analysis.monday' }, | ||
| 58 | - { value: 34235, name: 'analysis.tuesday' }, | ||
| 59 | - { value: 26321, name: 'analysis.wednesday' }, | ||
| 60 | - { value: 12340, name: 'analysis.thursday' }, | ||
| 61 | - { value: 24643, name: 'analysis.friday' }, | ||
| 62 | - { value: 1322, name: 'analysis.saturday' }, | ||
| 63 | - { value: 1324, name: 'analysis.sunday' } | ||
| 64 | - ] | ||
| 65 | - set( | ||
| 66 | - barOptionsData, | ||
| 67 | - 'xAxis.data', | ||
| 68 | - data.map((v) => t(v.name)) | ||
| 69 | - ) | ||
| 70 | - set(barOptionsData, 'series', [ | ||
| 71 | - { | ||
| 72 | - name: t('analysis.activeQuantity'), | ||
| 73 | - data: data.map((v) => v.value), | ||
| 74 | - type: 'bar' | ||
| 75 | - } | ||
| 76 | - ]) | ||
| 77 | -} | ||
| 78 | - | ||
| 79 | -const lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption | ||
| 80 | - | ||
| 81 | -// 每月销售总额 | ||
| 82 | -const getMonthlySales = async () => { | ||
| 83 | - const data = [ | ||
| 84 | - { estimate: 100, actual: 120, name: 'analysis.january' }, | ||
| 85 | - { estimate: 120, actual: 82, name: 'analysis.february' }, | ||
| 86 | - { estimate: 161, actual: 91, name: 'analysis.march' }, | ||
| 87 | - { estimate: 134, actual: 154, name: 'analysis.april' }, | ||
| 88 | - { estimate: 105, actual: 162, name: 'analysis.may' }, | ||
| 89 | - { estimate: 160, actual: 140, name: 'analysis.june' }, | ||
| 90 | - { estimate: 165, actual: 145, name: 'analysis.july' }, | ||
| 91 | - { estimate: 114, actual: 250, name: 'analysis.august' }, | ||
| 92 | - { estimate: 163, actual: 134, name: 'analysis.september' }, | ||
| 93 | - { estimate: 185, actual: 56, name: 'analysis.october' }, | ||
| 94 | - { estimate: 118, actual: 99, name: 'analysis.november' }, | ||
| 95 | - { estimate: 123, actual: 123, name: 'analysis.december' } | ||
| 96 | - ] | ||
| 97 | - set( | ||
| 98 | - lineOptionsData, | ||
| 99 | - 'xAxis.data', | ||
| 100 | - data.map((v) => t(v.name)) | ||
| 101 | - ) | ||
| 102 | - set(lineOptionsData, 'series', [ | ||
| 103 | - { | ||
| 104 | - name: t('analysis.estimate'), | ||
| 105 | - smooth: true, | ||
| 106 | - type: 'line', | ||
| 107 | - data: data.map((v) => v.estimate), | ||
| 108 | - animationDuration: 2800, | ||
| 109 | - animationEasing: 'cubicInOut' | ||
| 110 | - }, | ||
| 111 | - { | ||
| 112 | - name: t('analysis.actual'), | ||
| 113 | - smooth: true, | ||
| 114 | - type: 'line', | ||
| 115 | - itemStyle: {}, | ||
| 116 | - data: data.map((v) => v.actual), | ||
| 117 | - animationDuration: 2800, | ||
| 118 | - animationEasing: 'quadraticOut' | ||
| 119 | - } | ||
| 120 | - ]) | ||
| 121 | -} | ||
| 122 | - | ||
| 123 | -const getAllApi = async () => { | ||
| 124 | - await Promise.all([getCount(), getUserAccessSource(), getWeeklyUserActivity(), getMonthlySales()]) | ||
| 125 | - loading.value = false | ||
| 126 | -} | ||
| 127 | - | ||
| 128 | -getAllApi() | ||
| 129 | -</script> | ||
| 130 | - | ||
| 131 | <template> | 1 | <template> |
| 132 | <el-row :gutter="20" justify="space-between" :class="prefixCls"> | 2 | <el-row :gutter="20" justify="space-between" :class="prefixCls"> |
| 133 | <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24"> | 3 | <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24"> |
| @@ -270,6 +140,136 @@ getAllApi() | @@ -270,6 +140,136 @@ getAllApi() | ||
| 270 | </el-col> | 140 | </el-col> |
| 271 | </el-row> | 141 | </el-row> |
| 272 | </template> | 142 | </template> |
| 143 | +<script setup lang="ts"> | ||
| 144 | +import { ref, reactive } from 'vue' | ||
| 145 | +import { set } from 'lodash-es' | ||
| 146 | +import { EChartsOption } from 'echarts' | ||
| 147 | +import { Echart } from '@/components/Echart' | ||
| 148 | +import { useI18n } from '@/hooks/web/useI18n' | ||
| 149 | +import { CountTo } from '@/components/CountTo' | ||
| 150 | +import type { AnalysisTotalTypes } from './types' | ||
| 151 | +import { useDesign } from '@/hooks/web/useDesign' | ||
| 152 | +import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus' | ||
| 153 | +import { pieOptions, barOptions, lineOptions } from './echarts-data' | ||
| 154 | + | ||
| 155 | +const { t } = useI18n() | ||
| 156 | +const loading = ref(true) | ||
| 157 | +const { getPrefixCls } = useDesign() | ||
| 158 | +const prefixCls = getPrefixCls('panel') | ||
| 159 | +const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption | ||
| 160 | + | ||
| 161 | +let totalState = reactive<AnalysisTotalTypes>({ | ||
| 162 | + users: 0, | ||
| 163 | + messages: 0, | ||
| 164 | + moneys: 0, | ||
| 165 | + shoppings: 0 | ||
| 166 | +}) | ||
| 167 | + | ||
| 168 | +const getCount = async () => { | ||
| 169 | + const data = { | ||
| 170 | + users: 102400, | ||
| 171 | + messages: 81212, | ||
| 172 | + moneys: 9280, | ||
| 173 | + shoppings: 13600 | ||
| 174 | + } | ||
| 175 | + totalState = Object.assign(totalState, data) | ||
| 176 | +} | ||
| 177 | + | ||
| 178 | +// 用户来源 | ||
| 179 | +const getUserAccessSource = async () => { | ||
| 180 | + const data = [ | ||
| 181 | + { value: 335, name: 'analysis.directAccess' }, | ||
| 182 | + { value: 310, name: 'analysis.mailMarketing' }, | ||
| 183 | + { value: 234, name: 'analysis.allianceAdvertising' }, | ||
| 184 | + { value: 135, name: 'analysis.videoAdvertising' }, | ||
| 185 | + { value: 1548, name: 'analysis.searchEngines' } | ||
| 186 | + ] | ||
| 187 | + set( | ||
| 188 | + pieOptionsData, | ||
| 189 | + 'legend.data', | ||
| 190 | + data.map((v) => t(v.name)) | ||
| 191 | + ) | ||
| 192 | + set(pieOptionsData, 'series.data', data) | ||
| 193 | +} | ||
| 194 | +const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption | ||
| 195 | + | ||
| 196 | +// 周活跃量 | ||
| 197 | +const getWeeklyUserActivity = async () => { | ||
| 198 | + const data = [ | ||
| 199 | + { value: 13253, name: 'analysis.monday' }, | ||
| 200 | + { value: 34235, name: 'analysis.tuesday' }, | ||
| 201 | + { value: 26321, name: 'analysis.wednesday' }, | ||
| 202 | + { value: 12340, name: 'analysis.thursday' }, | ||
| 203 | + { value: 24643, name: 'analysis.friday' }, | ||
| 204 | + { value: 1322, name: 'analysis.saturday' }, | ||
| 205 | + { value: 1324, name: 'analysis.sunday' } | ||
| 206 | + ] | ||
| 207 | + set( | ||
| 208 | + barOptionsData, | ||
| 209 | + 'xAxis.data', | ||
| 210 | + data.map((v) => t(v.name)) | ||
| 211 | + ) | ||
| 212 | + set(barOptionsData, 'series', [ | ||
| 213 | + { | ||
| 214 | + name: t('analysis.activeQuantity'), | ||
| 215 | + data: data.map((v) => v.value), | ||
| 216 | + type: 'bar' | ||
| 217 | + } | ||
| 218 | + ]) | ||
| 219 | +} | ||
| 220 | + | ||
| 221 | +const lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption | ||
| 222 | + | ||
| 223 | +// 每月销售总额 | ||
| 224 | +const getMonthlySales = async () => { | ||
| 225 | + const data = [ | ||
| 226 | + { estimate: 100, actual: 120, name: 'analysis.january' }, | ||
| 227 | + { estimate: 120, actual: 82, name: 'analysis.february' }, | ||
| 228 | + { estimate: 161, actual: 91, name: 'analysis.march' }, | ||
| 229 | + { estimate: 134, actual: 154, name: 'analysis.april' }, | ||
| 230 | + { estimate: 105, actual: 162, name: 'analysis.may' }, | ||
| 231 | + { estimate: 160, actual: 140, name: 'analysis.june' }, | ||
| 232 | + { estimate: 165, actual: 145, name: 'analysis.july' }, | ||
| 233 | + { estimate: 114, actual: 250, name: 'analysis.august' }, | ||
| 234 | + { estimate: 163, actual: 134, name: 'analysis.september' }, | ||
| 235 | + { estimate: 185, actual: 56, name: 'analysis.october' }, | ||
| 236 | + { estimate: 118, actual: 99, name: 'analysis.november' }, | ||
| 237 | + { estimate: 123, actual: 123, name: 'analysis.december' } | ||
| 238 | + ] | ||
| 239 | + set( | ||
| 240 | + lineOptionsData, | ||
| 241 | + 'xAxis.data', | ||
| 242 | + data.map((v) => t(v.name)) | ||
| 243 | + ) | ||
| 244 | + set(lineOptionsData, 'series', [ | ||
| 245 | + { | ||
| 246 | + name: t('analysis.estimate'), | ||
| 247 | + smooth: true, | ||
| 248 | + type: 'line', | ||
| 249 | + data: data.map((v) => v.estimate), | ||
| 250 | + animationDuration: 2800, | ||
| 251 | + animationEasing: 'cubicInOut' | ||
| 252 | + }, | ||
| 253 | + { | ||
| 254 | + name: t('analysis.actual'), | ||
| 255 | + smooth: true, | ||
| 256 | + type: 'line', | ||
| 257 | + itemStyle: {}, | ||
| 258 | + data: data.map((v) => v.actual), | ||
| 259 | + animationDuration: 2800, | ||
| 260 | + animationEasing: 'quadraticOut' | ||
| 261 | + } | ||
| 262 | + ]) | ||
| 263 | +} | ||
| 264 | + | ||
| 265 | +const getAllApi = async () => { | ||
| 266 | + await Promise.all([getCount(), getUserAccessSource(), getWeeklyUserActivity(), getMonthlySales()]) | ||
| 267 | + loading.value = false | ||
| 268 | +} | ||
| 269 | + | ||
| 270 | +getAllApi() | ||
| 271 | +</script> | ||
| 272 | + | ||
| 273 | <style lang="less" scoped> | 273 | <style lang="less" scoped> |
| 274 | @prefix-cls: ~'@{namespace}-panel'; | 274 | @prefix-cls: ~'@{namespace}-panel'; |
| 275 | 275 |
yudao-ui-admin-vue3/src/views/Login/Login.vue
| 1 | -<script setup lang="ts"> | ||
| 2 | -import { LoginForm, MobileForm, RegisterForm, QrCodeForm } from './components' | ||
| 3 | -import { ThemeSwitch } from '@/components/ThemeSwitch' | ||
| 4 | -import { LocaleDropdown } from '@/components/LocaleDropdown' | ||
| 5 | -import { useI18n } from '@/hooks/web/useI18n' | ||
| 6 | -import { underlineToHump } from '@/utils' | ||
| 7 | -import { useAppStore } from '@/store/modules/app' | ||
| 8 | -import { useDesign } from '@/hooks/web/useDesign' | ||
| 9 | - | ||
| 10 | -const { t } = useI18n() | ||
| 11 | - | ||
| 12 | -const { getPrefixCls } = useDesign() | ||
| 13 | - | ||
| 14 | -const prefixCls = getPrefixCls('login') | ||
| 15 | - | ||
| 16 | -const appStore = useAppStore() | ||
| 17 | -</script> | ||
| 18 | - | ||
| 19 | <template> | 1 | <template> |
| 20 | <div | 2 | <div |
| 21 | :class="prefixCls" | 3 | :class="prefixCls" |
| @@ -76,6 +58,23 @@ const appStore = useAppStore() | @@ -76,6 +58,23 @@ const appStore = useAppStore() | ||
| 76 | </div> | 58 | </div> |
| 77 | </div> | 59 | </div> |
| 78 | </template> | 60 | </template> |
| 61 | +<script setup lang="ts"> | ||
| 62 | +import { LoginForm, MobileForm, RegisterForm, QrCodeForm } from './components' | ||
| 63 | +import { ThemeSwitch } from '@/components/ThemeSwitch' | ||
| 64 | +import { LocaleDropdown } from '@/components/LocaleDropdown' | ||
| 65 | +import { useI18n } from '@/hooks/web/useI18n' | ||
| 66 | +import { underlineToHump } from '@/utils' | ||
| 67 | +import { useAppStore } from '@/store/modules/app' | ||
| 68 | +import { useDesign } from '@/hooks/web/useDesign' | ||
| 69 | + | ||
| 70 | +const { t } = useI18n() | ||
| 71 | + | ||
| 72 | +const { getPrefixCls } = useDesign() | ||
| 73 | + | ||
| 74 | +const prefixCls = getPrefixCls('login') | ||
| 75 | + | ||
| 76 | +const appStore = useAppStore() | ||
| 77 | +</script> | ||
| 79 | 78 | ||
| 80 | <style lang="less" scoped> | 79 | <style lang="less" scoped> |
| 81 | @prefix-cls: ~'@{namespace}-login'; | 80 | @prefix-cls: ~'@{namespace}-login'; |
yudao-ui-admin-vue3/src/views/Login/components/LoginForm.vue
| 1 | +<template> | ||
| 2 | + <el-form | ||
| 3 | + :model="loginData.loginForm" | ||
| 4 | + :rules="LoginRules" | ||
| 5 | + label-position="top" | ||
| 6 | + class="login-form" | ||
| 7 | + label-width="120px" | ||
| 8 | + size="large" | ||
| 9 | + v-show="getShow" | ||
| 10 | + ref="formLogin" | ||
| 11 | + > | ||
| 12 | + <el-row style="maring-left: -10px; maring-right: -10px"> | ||
| 13 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 14 | + <el-form-item> | ||
| 15 | + <LoginFormTitle style="width: 100%" /> | ||
| 16 | + </el-form-item> | ||
| 17 | + </el-col> | ||
| 18 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 19 | + <el-form-item prop="tenantName"> | ||
| 20 | + <el-input | ||
| 21 | + type="text" | ||
| 22 | + v-model="loginData.loginForm.tenantName" | ||
| 23 | + :placeholder="t('login.tenantNamePlaceholder')" | ||
| 24 | + :prefix-icon="iconHouse" | ||
| 25 | + /> | ||
| 26 | + </el-form-item> | ||
| 27 | + </el-col> | ||
| 28 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 29 | + <el-form-item prop="username"> | ||
| 30 | + <el-input | ||
| 31 | + v-model="loginData.loginForm.username" | ||
| 32 | + :placeholder="t('login.usernamePlaceholder')" | ||
| 33 | + :prefix-icon="iconAvatar" | ||
| 34 | + /> | ||
| 35 | + </el-form-item> | ||
| 36 | + </el-col> | ||
| 37 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 38 | + <el-form-item prop="password"> | ||
| 39 | + <el-input | ||
| 40 | + v-model="loginData.loginForm.password" | ||
| 41 | + type="password" | ||
| 42 | + :placeholder="t('login.passwordPlaceholder')" | ||
| 43 | + show-password | ||
| 44 | + @keyup.enter="getCode()" | ||
| 45 | + :prefix-icon="iconLock" | ||
| 46 | + /> | ||
| 47 | + </el-form-item> | ||
| 48 | + </el-col> | ||
| 49 | + <el-col | ||
| 50 | + :span="24" | ||
| 51 | + style="padding-left: 10px; padding-right: 10px; margin-top: -20px; margin-bottom: -20px" | ||
| 52 | + > | ||
| 53 | + <el-form-item> | ||
| 54 | + <el-row justify="space-between" style="width: 100%"> | ||
| 55 | + <el-col :span="6"> | ||
| 56 | + <el-checkbox v-model="loginData.loginForm.rememberMe"> | ||
| 57 | + {{ t('login.remember') }} | ||
| 58 | + </el-checkbox> | ||
| 59 | + </el-col> | ||
| 60 | + <el-col :span="12" :offset="6"> | ||
| 61 | + <el-link type="primary" style="float: right">{{ t('login.forgetPassword') }}</el-link> | ||
| 62 | + </el-col> | ||
| 63 | + </el-row> | ||
| 64 | + </el-form-item> | ||
| 65 | + </el-col> | ||
| 66 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 67 | + <el-form-item> | ||
| 68 | + <el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="getCode()"> | ||
| 69 | + {{ t('login.login') }} | ||
| 70 | + </el-button> | ||
| 71 | + </el-form-item> | ||
| 72 | + </el-col> | ||
| 73 | + <Verify | ||
| 74 | + ref="verify" | ||
| 75 | + mode="pop" | ||
| 76 | + :captchaType="captchaType" | ||
| 77 | + :imgSize="{ width: '400px', height: '200px' }" | ||
| 78 | + @success="handleLogin" | ||
| 79 | + /> | ||
| 80 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 81 | + <el-form-item> | ||
| 82 | + <el-row justify="space-between" style="width: 100%" :gutter="5"> | ||
| 83 | + <el-col :span="8"> | ||
| 84 | + <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.MOBILE)"> | ||
| 85 | + {{ t('login.btnMobile') }} | ||
| 86 | + </el-button> | ||
| 87 | + </el-col> | ||
| 88 | + <el-col :span="8"> | ||
| 89 | + <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.QR_CODE)"> | ||
| 90 | + {{ t('login.btnQRCode') }} | ||
| 91 | + </el-button> | ||
| 92 | + </el-col> | ||
| 93 | + <el-col :span="8"> | ||
| 94 | + <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.REGISTER)"> | ||
| 95 | + {{ t('login.btnRegister') }} | ||
| 96 | + </el-button> | ||
| 97 | + </el-col> | ||
| 98 | + </el-row> | ||
| 99 | + </el-form-item> | ||
| 100 | + </el-col> | ||
| 101 | + <el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider> | ||
| 102 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 103 | + <el-form-item> | ||
| 104 | + <div class="flex justify-between w-[100%]"> | ||
| 105 | + <Icon | ||
| 106 | + icon="ant-design:github-filled" | ||
| 107 | + :size="iconSize" | ||
| 108 | + class="cursor-pointer anticon" | ||
| 109 | + :color="iconColor" | ||
| 110 | + @click="doSocialLogin('github')" | ||
| 111 | + /> | ||
| 112 | + <Icon | ||
| 113 | + icon="ant-design:wechat-filled" | ||
| 114 | + :size="iconSize" | ||
| 115 | + class="cursor-pointer anticon" | ||
| 116 | + :color="iconColor" | ||
| 117 | + @click="doSocialLogin('wechat')" | ||
| 118 | + /> | ||
| 119 | + <Icon | ||
| 120 | + icon="ant-design:alipay-circle-filled" | ||
| 121 | + :size="iconSize" | ||
| 122 | + :color="iconColor" | ||
| 123 | + class="cursor-pointer anticon" | ||
| 124 | + @click="doSocialLogin('alipay')" | ||
| 125 | + /> | ||
| 126 | + <Icon | ||
| 127 | + icon="ant-design:dingtalk-circle-filled" | ||
| 128 | + :size="iconSize" | ||
| 129 | + :color="iconColor" | ||
| 130 | + class="cursor-pointer anticon" | ||
| 131 | + @click="doSocialLogin('dingtalk')" | ||
| 132 | + /> | ||
| 133 | + </div> | ||
| 134 | + </el-form-item> | ||
| 135 | + </el-col> | ||
| 136 | + </el-row> | ||
| 137 | + </el-form> | ||
| 138 | +</template> | ||
| 1 | <script setup lang="ts"> | 139 | <script setup lang="ts"> |
| 2 | import { useIcon } from '@/hooks/web/useIcon' | 140 | import { useIcon } from '@/hooks/web/useIcon' |
| 3 | import LoginFormTitle from './LoginFormTitle.vue' | 141 | import LoginFormTitle from './LoginFormTitle.vue' |
| @@ -153,144 +291,7 @@ onMounted(() => { | @@ -153,144 +291,7 @@ onMounted(() => { | ||
| 153 | getCookie() | 291 | getCookie() |
| 154 | }) | 292 | }) |
| 155 | </script> | 293 | </script> |
| 156 | -<template> | ||
| 157 | - <el-form | ||
| 158 | - :model="loginData.loginForm" | ||
| 159 | - :rules="LoginRules" | ||
| 160 | - label-position="top" | ||
| 161 | - class="login-form" | ||
| 162 | - label-width="120px" | ||
| 163 | - size="large" | ||
| 164 | - v-show="getShow" | ||
| 165 | - ref="formLogin" | ||
| 166 | - > | ||
| 167 | - <el-row style="maring-left: -10px; maring-right: -10px"> | ||
| 168 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 169 | - <el-form-item> | ||
| 170 | - <LoginFormTitle style="width: 100%" /> | ||
| 171 | - </el-form-item> | ||
| 172 | - </el-col> | ||
| 173 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 174 | - <el-form-item prop="tenantName"> | ||
| 175 | - <el-input | ||
| 176 | - type="text" | ||
| 177 | - v-model="loginData.loginForm.tenantName" | ||
| 178 | - :placeholder="t('login.tenantNamePlaceholder')" | ||
| 179 | - :prefix-icon="iconHouse" | ||
| 180 | - /> | ||
| 181 | - </el-form-item> | ||
| 182 | - </el-col> | ||
| 183 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 184 | - <el-form-item prop="username"> | ||
| 185 | - <el-input | ||
| 186 | - v-model="loginData.loginForm.username" | ||
| 187 | - :placeholder="t('login.usernamePlaceholder')" | ||
| 188 | - :prefix-icon="iconAvatar" | ||
| 189 | - /> | ||
| 190 | - </el-form-item> | ||
| 191 | - </el-col> | ||
| 192 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 193 | - <el-form-item prop="password"> | ||
| 194 | - <el-input | ||
| 195 | - v-model="loginData.loginForm.password" | ||
| 196 | - type="password" | ||
| 197 | - :placeholder="t('login.passwordPlaceholder')" | ||
| 198 | - show-password | ||
| 199 | - @keyup.enter="getCode()" | ||
| 200 | - :prefix-icon="iconLock" | ||
| 201 | - /> | ||
| 202 | - </el-form-item> | ||
| 203 | - </el-col> | ||
| 204 | - <el-col | ||
| 205 | - :span="24" | ||
| 206 | - style="padding-left: 10px; padding-right: 10px; margin-top: -20px; margin-bottom: -20px" | ||
| 207 | - > | ||
| 208 | - <el-form-item> | ||
| 209 | - <el-row justify="space-between" style="width: 100%"> | ||
| 210 | - <el-col :span="6"> | ||
| 211 | - <el-checkbox v-model="loginData.loginForm.rememberMe"> | ||
| 212 | - {{ t('login.remember') }} | ||
| 213 | - </el-checkbox> | ||
| 214 | - </el-col> | ||
| 215 | - <el-col :span="12" :offset="6"> | ||
| 216 | - <el-link type="primary" style="float: right">{{ t('login.forgetPassword') }}</el-link> | ||
| 217 | - </el-col> | ||
| 218 | - </el-row> | ||
| 219 | - </el-form-item> | ||
| 220 | - </el-col> | ||
| 221 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 222 | - <el-form-item> | ||
| 223 | - <el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="getCode()"> | ||
| 224 | - {{ t('login.login') }} | ||
| 225 | - </el-button> | ||
| 226 | - </el-form-item> | ||
| 227 | - </el-col> | ||
| 228 | - <Verify | ||
| 229 | - ref="verify" | ||
| 230 | - mode="pop" | ||
| 231 | - :captchaType="captchaType" | ||
| 232 | - :imgSize="{ width: '400px', height: '200px' }" | ||
| 233 | - @success="handleLogin" | ||
| 234 | - /> | ||
| 235 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 236 | - <el-form-item> | ||
| 237 | - <el-row justify="space-between" style="width: 100%" :gutter="5"> | ||
| 238 | - <el-col :span="8"> | ||
| 239 | - <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.MOBILE)"> | ||
| 240 | - {{ t('login.btnMobile') }} | ||
| 241 | - </el-button> | ||
| 242 | - </el-col> | ||
| 243 | - <el-col :span="8"> | ||
| 244 | - <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.QR_CODE)"> | ||
| 245 | - {{ t('login.btnQRCode') }} | ||
| 246 | - </el-button> | ||
| 247 | - </el-col> | ||
| 248 | - <el-col :span="8"> | ||
| 249 | - <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.REGISTER)"> | ||
| 250 | - {{ t('login.btnRegister') }} | ||
| 251 | - </el-button> | ||
| 252 | - </el-col> | ||
| 253 | - </el-row> | ||
| 254 | - </el-form-item> | ||
| 255 | - </el-col> | ||
| 256 | - <el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider> | ||
| 257 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 258 | - <el-form-item> | ||
| 259 | - <div class="flex justify-between w-[100%]"> | ||
| 260 | - <Icon | ||
| 261 | - icon="ant-design:github-filled" | ||
| 262 | - :size="iconSize" | ||
| 263 | - class="cursor-pointer anticon" | ||
| 264 | - :color="iconColor" | ||
| 265 | - @click="doSocialLogin('github')" | ||
| 266 | - /> | ||
| 267 | - <Icon | ||
| 268 | - icon="ant-design:wechat-filled" | ||
| 269 | - :size="iconSize" | ||
| 270 | - class="cursor-pointer anticon" | ||
| 271 | - :color="iconColor" | ||
| 272 | - @click="doSocialLogin('wechat')" | ||
| 273 | - /> | ||
| 274 | - <Icon | ||
| 275 | - icon="ant-design:alipay-circle-filled" | ||
| 276 | - :size="iconSize" | ||
| 277 | - :color="iconColor" | ||
| 278 | - class="cursor-pointer anticon" | ||
| 279 | - @click="doSocialLogin('alipay')" | ||
| 280 | - /> | ||
| 281 | - <Icon | ||
| 282 | - icon="ant-design:dingtalk-circle-filled" | ||
| 283 | - :size="iconSize" | ||
| 284 | - :color="iconColor" | ||
| 285 | - class="cursor-pointer anticon" | ||
| 286 | - @click="doSocialLogin('dingtalk')" | ||
| 287 | - /> | ||
| 288 | - </div> | ||
| 289 | - </el-form-item> | ||
| 290 | - </el-col> | ||
| 291 | - </el-row> | ||
| 292 | - </el-form> | ||
| 293 | -</template> | 294 | + |
| 294 | <style lang="less" scoped> | 295 | <style lang="less" scoped> |
| 295 | :deep(.anticon) { | 296 | :deep(.anticon) { |
| 296 | &:hover { | 297 | &:hover { |
yudao-ui-admin-vue3/src/views/Login/components/LoginFormTitle.vue
| 1 | +<template> | ||
| 2 | + <h2 class="mb-3 text-2xl font-bold text-center xl:text-3xl enter-x xl:text-center"> | ||
| 3 | + {{ getFormTitle }} | ||
| 4 | + </h2> | ||
| 5 | +</template> | ||
| 1 | <script setup lang="ts"> | 6 | <script setup lang="ts"> |
| 2 | import { computed, unref } from 'vue' | 7 | import { computed, unref } from 'vue' |
| 3 | import { useI18n } from '@/hooks/web/useI18n' | 8 | import { useI18n } from '@/hooks/web/useI18n' |
| @@ -18,8 +23,3 @@ const getFormTitle = computed(() => { | @@ -18,8 +23,3 @@ const getFormTitle = computed(() => { | ||
| 18 | return titleObj[unref(getLoginState)] | 23 | return titleObj[unref(getLoginState)] |
| 19 | }) | 24 | }) |
| 20 | </script> | 25 | </script> |
| 21 | -<template> | ||
| 22 | - <h2 class="mb-3 text-2xl font-bold text-center xl:text-3xl enter-x xl:text-center"> | ||
| 23 | - {{ getFormTitle }} | ||
| 24 | - </h2> | ||
| 25 | -</template> |
yudao-ui-admin-vue3/src/views/Login/components/MobileForm.vue
| 1 | +<template> | ||
| 2 | + <el-form | ||
| 3 | + :model="loginData.loginForm" | ||
| 4 | + :rules="rules" | ||
| 5 | + label-position="top" | ||
| 6 | + class="login-form" | ||
| 7 | + label-width="120px" | ||
| 8 | + size="large" | ||
| 9 | + v-show="getShow" | ||
| 10 | + ref="formSmsLogin" | ||
| 11 | + > | ||
| 12 | + <el-row style="margin-left: -10px; margin-right: -10px"> | ||
| 13 | + <!-- 租户名 --> | ||
| 14 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 15 | + <el-form-item> | ||
| 16 | + <LoginFormTitle style="width: 100%" /> | ||
| 17 | + </el-form-item> | ||
| 18 | + </el-col> | ||
| 19 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 20 | + <el-form-item prop="tenantName"> | ||
| 21 | + <el-input | ||
| 22 | + type="text" | ||
| 23 | + v-model="loginData.loginForm.tenantName" | ||
| 24 | + :placeholder="t('login.tenantNamePlaceholder')" | ||
| 25 | + :prefix-icon="iconHouse" | ||
| 26 | + /> | ||
| 27 | + </el-form-item> | ||
| 28 | + </el-col> | ||
| 29 | + <!-- 手机号 --> | ||
| 30 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 31 | + <el-form-item prop="mobileNumber"> | ||
| 32 | + <el-input | ||
| 33 | + v-model="loginData.loginForm.mobileNumber" | ||
| 34 | + :placeholder="t('login.mobileNumberPlaceholder')" | ||
| 35 | + :prefix-icon="iconCellphone" | ||
| 36 | + /> | ||
| 37 | + </el-form-item> | ||
| 38 | + </el-col> | ||
| 39 | + <!-- 验证码 --> | ||
| 40 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 41 | + <el-form-item prop="code"> | ||
| 42 | + <el-row justify="space-between" style="width: 100%" :gutter="5"> | ||
| 43 | + <el-col :span="24"> | ||
| 44 | + <el-input | ||
| 45 | + v-model="loginData.loginForm.code" | ||
| 46 | + :placeholder="t('login.codePlaceholder')" | ||
| 47 | + :prefix-icon="iconCircleCheck" | ||
| 48 | + > | ||
| 49 | + <!-- <el-button class="w-[100%]"> --> | ||
| 50 | + <template #append> | ||
| 51 | + <span | ||
| 52 | + v-if="mobileCodeTimer <= 0" | ||
| 53 | + @click="getSmsCode" | ||
| 54 | + class="getMobileCode" | ||
| 55 | + style="cursor: pointer" | ||
| 56 | + > | ||
| 57 | + {{ t('login.getSmsCode') }} | ||
| 58 | + </span> | ||
| 59 | + <span v-if="mobileCodeTimer > 0" class="getMobileCode" style="cursor: pointer"> | ||
| 60 | + {{ mobileCodeTimer }}秒后可重新获取 | ||
| 61 | + </span> | ||
| 62 | + </template> | ||
| 63 | + </el-input> | ||
| 64 | + <!-- </el-button> --> | ||
| 65 | + </el-col> | ||
| 66 | + </el-row> | ||
| 67 | + </el-form-item> | ||
| 68 | + </el-col> | ||
| 69 | + <!-- 登录按钮 / 返回按钮 --> | ||
| 70 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 71 | + <el-form-item> | ||
| 72 | + <el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="signIn"> | ||
| 73 | + {{ t('login.login') }} | ||
| 74 | + </el-button> | ||
| 75 | + </el-form-item> | ||
| 76 | + </el-col> | ||
| 77 | + <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 78 | + <el-form-item> | ||
| 79 | + <el-button :loading="loginLoading" class="w-[100%]" @click="handleBackLogin"> | ||
| 80 | + {{ t('login.backLogin') }} | ||
| 81 | + </el-button> | ||
| 82 | + </el-form-item> | ||
| 83 | + </el-col> | ||
| 84 | + </el-row> | ||
| 85 | + </el-form> | ||
| 86 | +</template> | ||
| 1 | <script setup lang="ts"> | 87 | <script setup lang="ts"> |
| 2 | import { useIcon } from '@/hooks/web/useIcon' | 88 | import { useIcon } from '@/hooks/web/useIcon' |
| 3 | import { reactive, ref, unref, watch, computed } from 'vue' | 89 | import { reactive, ref, unref, watch, computed } from 'vue' |
| @@ -111,92 +197,7 @@ const signIn = async () => { | @@ -111,92 +197,7 @@ const signIn = async () => { | ||
| 111 | }) | 197 | }) |
| 112 | } | 198 | } |
| 113 | </script> | 199 | </script> |
| 114 | -<template> | ||
| 115 | - <el-form | ||
| 116 | - :model="loginData.loginForm" | ||
| 117 | - :rules="rules" | ||
| 118 | - label-position="top" | ||
| 119 | - class="login-form" | ||
| 120 | - label-width="120px" | ||
| 121 | - size="large" | ||
| 122 | - v-show="getShow" | ||
| 123 | - ref="formSmsLogin" | ||
| 124 | - > | ||
| 125 | - <el-row style="margin-left: -10px; margin-right: -10px"> | ||
| 126 | - <!-- 租户名 --> | ||
| 127 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 128 | - <el-form-item> | ||
| 129 | - <LoginFormTitle style="width: 100%" /> | ||
| 130 | - </el-form-item> | ||
| 131 | - </el-col> | ||
| 132 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 133 | - <el-form-item prop="tenantName"> | ||
| 134 | - <el-input | ||
| 135 | - type="text" | ||
| 136 | - v-model="loginData.loginForm.tenantName" | ||
| 137 | - :placeholder="t('login.tenantNamePlaceholder')" | ||
| 138 | - :prefix-icon="iconHouse" | ||
| 139 | - /> | ||
| 140 | - </el-form-item> | ||
| 141 | - </el-col> | ||
| 142 | - <!-- 手机号 --> | ||
| 143 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 144 | - <el-form-item prop="mobileNumber"> | ||
| 145 | - <el-input | ||
| 146 | - v-model="loginData.loginForm.mobileNumber" | ||
| 147 | - :placeholder="t('login.mobileNumberPlaceholder')" | ||
| 148 | - :prefix-icon="iconCellphone" | ||
| 149 | - /> | ||
| 150 | - </el-form-item> | ||
| 151 | - </el-col> | ||
| 152 | - <!-- 验证码 --> | ||
| 153 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 154 | - <el-form-item prop="code"> | ||
| 155 | - <el-row justify="space-between" style="width: 100%" :gutter="5"> | ||
| 156 | - <el-col :span="24"> | ||
| 157 | - <el-input | ||
| 158 | - v-model="loginData.loginForm.code" | ||
| 159 | - :placeholder="t('login.codePlaceholder')" | ||
| 160 | - :prefix-icon="iconCircleCheck" | ||
| 161 | - > | ||
| 162 | - <!-- <el-button class="w-[100%]"> --> | ||
| 163 | - <template #append> | ||
| 164 | - <span | ||
| 165 | - v-if="mobileCodeTimer <= 0" | ||
| 166 | - @click="getSmsCode" | ||
| 167 | - class="getMobileCode" | ||
| 168 | - style="cursor: pointer" | ||
| 169 | - > | ||
| 170 | - {{ t('login.getSmsCode') }} | ||
| 171 | - </span> | ||
| 172 | - <span v-if="mobileCodeTimer > 0" class="getMobileCode" style="cursor: pointer"> | ||
| 173 | - {{ mobileCodeTimer }}秒后可重新获取 | ||
| 174 | - </span> | ||
| 175 | - </template> | ||
| 176 | - </el-input> | ||
| 177 | - <!-- </el-button> --> | ||
| 178 | - </el-col> | ||
| 179 | - </el-row> | ||
| 180 | - </el-form-item> | ||
| 181 | - </el-col> | ||
| 182 | - <!-- 登录按钮 / 返回按钮 --> | ||
| 183 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 184 | - <el-form-item> | ||
| 185 | - <el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="signIn"> | ||
| 186 | - {{ t('login.login') }} | ||
| 187 | - </el-button> | ||
| 188 | - </el-form-item> | ||
| 189 | - </el-col> | ||
| 190 | - <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||
| 191 | - <el-form-item> | ||
| 192 | - <el-button :loading="loginLoading" class="w-[100%]" @click="handleBackLogin"> | ||
| 193 | - {{ t('login.backLogin') }} | ||
| 194 | - </el-button> | ||
| 195 | - </el-form-item> | ||
| 196 | - </el-col> | ||
| 197 | - </el-row> | ||
| 198 | - </el-form> | ||
| 199 | -</template> | 200 | + |
| 200 | <style lang="less" scoped> | 201 | <style lang="less" scoped> |
| 201 | :deep(.anticon) { | 202 | :deep(.anticon) { |
| 202 | &:hover { | 203 | &:hover { |
yudao-ui-admin-vue3/src/views/Login/components/QrCodeForm.vue
| 1 | -<script setup lang="ts"> | ||
| 2 | -import { computed, unref } from 'vue' | ||
| 3 | -import { ElRow, ElCol, ElCard, ElDivider } from 'element-plus' | ||
| 4 | -import { useI18n } from '@/hooks/web/useI18n' | ||
| 5 | -import { useLoginState, LoginStateEnum } from './useLogin' | ||
| 6 | -import LoginFormTitle from './LoginFormTitle.vue' | ||
| 7 | -import { Qrcode } from '@/components/Qrcode' | ||
| 8 | -import logoImg from '@/assets/imgs/logo.png' | ||
| 9 | - | ||
| 10 | -const { t } = useI18n() | ||
| 11 | -const { handleBackLogin, getLoginState } = useLoginState() | ||
| 12 | -const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE) | ||
| 13 | -</script> | ||
| 14 | - | ||
| 15 | <template> | 1 | <template> |
| 16 | <el-row v-show="getShow" style="maring-left: -10px; maring-right: -10px"> | 2 | <el-row v-show="getShow" style="maring-left: -10px; maring-right: -10px"> |
| 17 | <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | 3 | <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> |
| @@ -32,3 +18,16 @@ const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE) | @@ -32,3 +18,16 @@ const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE) | ||
| 32 | </el-col> | 18 | </el-col> |
| 33 | </el-row> | 19 | </el-row> |
| 34 | </template> | 20 | </template> |
| 21 | +<script setup lang="ts"> | ||
| 22 | +import { computed, unref } from 'vue' | ||
| 23 | +import { ElRow, ElCol, ElCard, ElDivider } from 'element-plus' | ||
| 24 | +import { useI18n } from '@/hooks/web/useI18n' | ||
| 25 | +import { useLoginState, LoginStateEnum } from './useLogin' | ||
| 26 | +import LoginFormTitle from './LoginFormTitle.vue' | ||
| 27 | +import { Qrcode } from '@/components/Qrcode' | ||
| 28 | +import logoImg from '@/assets/imgs/logo.png' | ||
| 29 | + | ||
| 30 | +const { t } = useI18n() | ||
| 31 | +const { handleBackLogin, getLoginState } = useLoginState() | ||
| 32 | +const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE) | ||
| 33 | +</script> |
yudao-ui-admin-vue3/src/views/Login/components/RegisterForm.vue
| 1 | +<template> | ||
| 2 | + <Form | ||
| 3 | + :schema="schema" | ||
| 4 | + :rules="rules" | ||
| 5 | + label-position="top" | ||
| 6 | + hide-required-asterisk | ||
| 7 | + size="large" | ||
| 8 | + v-show="getShow" | ||
| 9 | + class="dark:(border-1 border-[var(--el-border-color)] border-solid)" | ||
| 10 | + @register="register" | ||
| 11 | + > | ||
| 12 | + <template #title> | ||
| 13 | + <LoginFormTitle style="width: 100%" /> | ||
| 14 | + </template> | ||
| 15 | + | ||
| 16 | + <template #code="form"> | ||
| 17 | + <div class="w-[100%] flex"> | ||
| 18 | + <el-input v-model="form['code']" :placeholder="t('login.codePlaceholder')" /> | ||
| 19 | + </div> | ||
| 20 | + </template> | ||
| 21 | + | ||
| 22 | + <template #register> | ||
| 23 | + <div class="w-[100%]"> | ||
| 24 | + <el-button type="primary" class="w-[100%]" :loading="loading" @click="loginRegister"> | ||
| 25 | + {{ t('login.register') }} | ||
| 26 | + </el-button> | ||
| 27 | + </div> | ||
| 28 | + <div class="w-[100%] mt-15px"> | ||
| 29 | + <el-button class="w-[100%]" @click="handleBackLogin"> | ||
| 30 | + {{ t('login.hasUser') }} | ||
| 31 | + </el-button> | ||
| 32 | + </div> | ||
| 33 | + </template> | ||
| 34 | + </Form> | ||
| 35 | +</template> | ||
| 36 | + | ||
| 1 | <script setup lang="ts"> | 37 | <script setup lang="ts"> |
| 2 | import { Form } from '@/components/Form' | 38 | import { Form } from '@/components/Form' |
| 3 | import { computed, reactive, ref, unref } from 'vue' | 39 | import { computed, reactive, ref, unref } from 'vue' |
| @@ -104,39 +140,3 @@ const loginRegister = async () => { | @@ -104,39 +140,3 @@ const loginRegister = async () => { | ||
| 104 | }) | 140 | }) |
| 105 | } | 141 | } |
| 106 | </script> | 142 | </script> |
| 107 | - | ||
| 108 | -<template> | ||
| 109 | - <Form | ||
| 110 | - :schema="schema" | ||
| 111 | - :rules="rules" | ||
| 112 | - label-position="top" | ||
| 113 | - hide-required-asterisk | ||
| 114 | - size="large" | ||
| 115 | - v-show="getShow" | ||
| 116 | - class="dark:(border-1 border-[var(--el-border-color)] border-solid)" | ||
| 117 | - @register="register" | ||
| 118 | - > | ||
| 119 | - <template #title> | ||
| 120 | - <LoginFormTitle style="width: 100%" /> | ||
| 121 | - </template> | ||
| 122 | - | ||
| 123 | - <template #code="form"> | ||
| 124 | - <div class="w-[100%] flex"> | ||
| 125 | - <el-input v-model="form['code']" :placeholder="t('login.codePlaceholder')" /> | ||
| 126 | - </div> | ||
| 127 | - </template> | ||
| 128 | - | ||
| 129 | - <template #register> | ||
| 130 | - <div class="w-[100%]"> | ||
| 131 | - <el-button type="primary" class="w-[100%]" :loading="loading" @click="loginRegister"> | ||
| 132 | - {{ t('login.register') }} | ||
| 133 | - </el-button> | ||
| 134 | - </div> | ||
| 135 | - <div class="w-[100%] mt-15px"> | ||
| 136 | - <el-button class="w-[100%]" @click="handleBackLogin"> | ||
| 137 | - {{ t('login.hasUser') }} | ||
| 138 | - </el-button> | ||
| 139 | - </div> | ||
| 140 | - </template> | ||
| 141 | - </Form> | ||
| 142 | -</template> |