mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 18:28:43 +08:00 
			
		
		
		
	style: 切换页面布局
This commit is contained in:
		| @@ -1,3 +1,6 @@ | ||||
| <template> | ||||
|   <Error type="403" @error-click="errorClick" /> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { Error } from '@/components/Error' | ||||
| import { useRouter } from 'vue-router' | ||||
| @@ -8,7 +11,3 @@ const errorClick = () => { | ||||
|   push('/') | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <Error type="403" @error-click="errorClick" /> | ||||
| </template> | ||||
|   | ||||
| @@ -1,3 +1,7 @@ | ||||
| <template> | ||||
|   <Error @error-click="errorClick" /> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { Error } from '@/components/Error' | ||||
| import { useRouter } from 'vue-router' | ||||
| @@ -8,7 +12,3 @@ const errorClick = () => { | ||||
|   push('/') | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <Error @error-click="errorClick" /> | ||||
| </template> | ||||
|   | ||||
| @@ -1,3 +1,7 @@ | ||||
| <template> | ||||
|   <Error type="500" @error-click="errorClick" /> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { Error } from '@/components/Error' | ||||
| import { useRouter } from 'vue-router' | ||||
| @@ -8,7 +12,3 @@ const errorClick = () => { | ||||
|   push('/') | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <Error type="500" @error-click="errorClick" /> | ||||
| </template> | ||||
|   | ||||
| @@ -1,3 +1,165 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <el-card shadow="never"> | ||||
|       <el-skeleton :loading="loading" animated> | ||||
|         <el-row :gutter="20" justify="space-between"> | ||||
|           <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> | ||||
|             <div class="flex items-center"> | ||||
|               <img :src="avatar" alt="" class="w-70px h-70px rounded-[50%] mr-20px" /> | ||||
|               <div> | ||||
|                 <div class="text-20px text-700"> | ||||
|                   {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }} | ||||
|                 </div> | ||||
|                 <div class="mt-10px text-14px text-gray-500"> | ||||
|                   {{ t('workplace.toady') }},20℃ - 32℃! | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </el-col> | ||||
|           <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> | ||||
|             <div class="flex h-70px items-center justify-end <sm:mt-10px"> | ||||
|               <div class="px-8px text-right"> | ||||
|                 <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.project') }}</div> | ||||
|                 <CountTo | ||||
|                   class="text-20px" | ||||
|                   :start-val="0" | ||||
|                   :end-val="totalSate.project" | ||||
|                   :duration="2600" | ||||
|                 /> | ||||
|               </div> | ||||
|               <el-divider direction="vertical" /> | ||||
|               <div class="px-8px text-right"> | ||||
|                 <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.toDo') }}</div> | ||||
|                 <CountTo | ||||
|                   class="text-20px" | ||||
|                   :start-val="0" | ||||
|                   :end-val="totalSate.todo" | ||||
|                   :duration="2600" | ||||
|                 /> | ||||
|               </div> | ||||
|               <el-divider direction="vertical" border-style="dashed" /> | ||||
|               <div class="px-8px text-right"> | ||||
|                 <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.access') }}</div> | ||||
|                 <CountTo | ||||
|                   class="text-20px" | ||||
|                   :start-val="0" | ||||
|                   :end-val="totalSate.access" | ||||
|                   :duration="2600" | ||||
|                 /> | ||||
|               </div> | ||||
|             </div> | ||||
|           </el-col> | ||||
|         </el-row> | ||||
|       </el-skeleton> | ||||
|     </el-card> | ||||
|   </div> | ||||
|  | ||||
|   <el-row class="mt-5px" :gutter="20" justify="space-between"> | ||||
|     <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-10px"> | ||||
|       <el-card shadow="never"> | ||||
|         <template #header> | ||||
|           <div class="flex justify-between h-3"> | ||||
|             <span>{{ t('workplace.project') }}</span> | ||||
|             <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link> | ||||
|           </div> | ||||
|         </template> | ||||
|         <el-skeleton :loading="loading" animated> | ||||
|           <el-row> | ||||
|             <el-col | ||||
|               v-for="(item, index) in projects" | ||||
|               :key="`card-${index}`" | ||||
|               :xl="8" | ||||
|               :lg="8" | ||||
|               :md="8" | ||||
|               :sm="24" | ||||
|               :xs="24" | ||||
|             > | ||||
|               <el-card shadow="hover"> | ||||
|                 <div class="flex items-center"> | ||||
|                   <Icon :icon="item.icon" :size="25" class="mr-10px" /> | ||||
|                   <span class="text-16px">{{ item.name }}</span> | ||||
|                 </div> | ||||
|                 <div class="mt-15px text-14px text-gray-400">{{ t(item.message) }}</div> | ||||
|                 <div class="mt-20px text-12px text-gray-400 flex justify-between"> | ||||
|                   <span>{{ item.personal }}</span> | ||||
|                   <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span> | ||||
|                 </div> | ||||
|               </el-card> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-skeleton> | ||||
|       </el-card> | ||||
|  | ||||
|       <el-card shadow="never" class="mt-5px"> | ||||
|         <el-skeleton :loading="loading" animated> | ||||
|           <el-row :gutter="20" justify="space-between"> | ||||
|             <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24"> | ||||
|               <el-card shadow="hover" class="mb-10px"> | ||||
|                 <el-skeleton :loading="loading" animated> | ||||
|                   <Echart :options="pieOptionsData" :height="280" /> | ||||
|                 </el-skeleton> | ||||
|               </el-card> | ||||
|             </el-col> | ||||
|             <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24"> | ||||
|               <el-card shadow="hover" class="mb-10px"> | ||||
|                 <el-skeleton :loading="loading" animated> | ||||
|                   <Echart :options="barOptionsData" :height="280" /> | ||||
|                 </el-skeleton> | ||||
|               </el-card> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-skeleton> | ||||
|       </el-card> | ||||
|     </el-col> | ||||
|     <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-10px"> | ||||
|       <el-card shadow="never"> | ||||
|         <template #header> | ||||
|           <div class="flex justify-between h-3"> | ||||
|             <span>{{ t('workplace.shortcutOperation') }}</span> | ||||
|           </div> | ||||
|         </template> | ||||
|         <el-skeleton :loading="loading" animated> | ||||
|           <el-row> | ||||
|             <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-10px"> | ||||
|               <div class="flex items-center"> | ||||
|                 <Icon :icon="item.icon" class="mr-10px" /> | ||||
|                 <el-link type="default" :underline="false" :href="item.url"> | ||||
|                   {{ item.name }} | ||||
|                 </el-link> | ||||
|               </div> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-skeleton> | ||||
|       </el-card> | ||||
|       <el-card shadow="never" class="mt-10px"> | ||||
|         <template #header> | ||||
|           <div class="flex justify-between h-3"> | ||||
|             <span>{{ t('workplace.notice') }}</span> | ||||
|             <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link> | ||||
|           </div> | ||||
|         </template> | ||||
|         <el-skeleton :loading="loading" animated> | ||||
|           <div v-for="(item, index) in notice" :key="`dynamics-${index}`"> | ||||
|             <div class="flex items-center"> | ||||
|               <img :src="avatar" alt="" class="w-35px h-35px rounded-[50%] mr-20px" /> | ||||
|               <div> | ||||
|                 <div class="text-14px"> | ||||
|                   <Highlight :keys="item.keys.map((v) => t(v))"> | ||||
|                     {{ item.type }} : {{ item.title }} | ||||
|                   </Highlight> | ||||
|                 </div> | ||||
|                 <div class="mt-15px text-12px text-gray-400"> | ||||
|                   {{ formatTime(item.date, 'yyyy-MM-dd') }} | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|             <el-divider /> | ||||
|           </div> | ||||
|         </el-skeleton> | ||||
|       </el-card> | ||||
|     </el-col> | ||||
|   </el-row> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { ElRow, ElCol, ElSkeleton, ElCard, ElDivider, ElLink } from 'element-plus' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| @@ -217,166 +379,3 @@ const getAllApi = async () => { | ||||
|  | ||||
| getAllApi() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div> | ||||
|     <el-card shadow="never"> | ||||
|       <el-skeleton :loading="loading" animated> | ||||
|         <el-row :gutter="20" justify="space-between"> | ||||
|           <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> | ||||
|             <div class="flex items-center"> | ||||
|               <img :src="avatar" alt="" class="w-70px h-70px rounded-[50%] mr-20px" /> | ||||
|               <div> | ||||
|                 <div class="text-20px text-700"> | ||||
|                   {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }} | ||||
|                 </div> | ||||
|                 <div class="mt-10px text-14px text-gray-500"> | ||||
|                   {{ t('workplace.toady') }},20℃ - 32℃! | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </el-col> | ||||
|           <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> | ||||
|             <div class="flex h-70px items-center justify-end <sm:mt-10px"> | ||||
|               <div class="px-8px text-right"> | ||||
|                 <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.project') }}</div> | ||||
|                 <CountTo | ||||
|                   class="text-20px" | ||||
|                   :start-val="0" | ||||
|                   :end-val="totalSate.project" | ||||
|                   :duration="2600" | ||||
|                 /> | ||||
|               </div> | ||||
|               <el-divider direction="vertical" /> | ||||
|               <div class="px-8px text-right"> | ||||
|                 <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.toDo') }}</div> | ||||
|                 <CountTo | ||||
|                   class="text-20px" | ||||
|                   :start-val="0" | ||||
|                   :end-val="totalSate.todo" | ||||
|                   :duration="2600" | ||||
|                 /> | ||||
|               </div> | ||||
|               <el-divider direction="vertical" border-style="dashed" /> | ||||
|               <div class="px-8px text-right"> | ||||
|                 <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.access') }}</div> | ||||
|                 <CountTo | ||||
|                   class="text-20px" | ||||
|                   :start-val="0" | ||||
|                   :end-val="totalSate.access" | ||||
|                   :duration="2600" | ||||
|                 /> | ||||
|               </div> | ||||
|             </div> | ||||
|           </el-col> | ||||
|         </el-row> | ||||
|       </el-skeleton> | ||||
|     </el-card> | ||||
|   </div> | ||||
|  | ||||
|   <el-row class="mt-5px" :gutter="20" justify="space-between"> | ||||
|     <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-10px"> | ||||
|       <el-card shadow="never"> | ||||
|         <template #header> | ||||
|           <div class="flex justify-between h-3"> | ||||
|             <span>{{ t('workplace.project') }}</span> | ||||
|             <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link> | ||||
|           </div> | ||||
|         </template> | ||||
|         <el-skeleton :loading="loading" animated> | ||||
|           <el-row> | ||||
|             <el-col | ||||
|               v-for="(item, index) in projects" | ||||
|               :key="`card-${index}`" | ||||
|               :xl="8" | ||||
|               :lg="8" | ||||
|               :md="8" | ||||
|               :sm="24" | ||||
|               :xs="24" | ||||
|             > | ||||
|               <el-card shadow="hover"> | ||||
|                 <div class="flex items-center"> | ||||
|                   <Icon :icon="item.icon" :size="25" class="mr-10px" /> | ||||
|                   <span class="text-16px">{{ item.name }}</span> | ||||
|                 </div> | ||||
|                 <div class="mt-15px text-14px text-gray-400">{{ t(item.message) }}</div> | ||||
|                 <div class="mt-20px text-12px text-gray-400 flex justify-between"> | ||||
|                   <span>{{ item.personal }}</span> | ||||
|                   <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span> | ||||
|                 </div> | ||||
|               </el-card> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-skeleton> | ||||
|       </el-card> | ||||
|  | ||||
|       <el-card shadow="never" class="mt-5px"> | ||||
|         <el-skeleton :loading="loading" animated> | ||||
|           <el-row :gutter="20" justify="space-between"> | ||||
|             <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24"> | ||||
|               <el-card shadow="hover" class="mb-10px"> | ||||
|                 <el-skeleton :loading="loading" animated> | ||||
|                   <Echart :options="pieOptionsData" :height="280" /> | ||||
|                 </el-skeleton> | ||||
|               </el-card> | ||||
|             </el-col> | ||||
|             <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24"> | ||||
|               <el-card shadow="hover" class="mb-10px"> | ||||
|                 <el-skeleton :loading="loading" animated> | ||||
|                   <Echart :options="barOptionsData" :height="280" /> | ||||
|                 </el-skeleton> | ||||
|               </el-card> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-skeleton> | ||||
|       </el-card> | ||||
|     </el-col> | ||||
|     <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-10px"> | ||||
|       <el-card shadow="never"> | ||||
|         <template #header> | ||||
|           <div class="flex justify-between h-3"> | ||||
|             <span>{{ t('workplace.shortcutOperation') }}</span> | ||||
|           </div> | ||||
|         </template> | ||||
|         <el-skeleton :loading="loading" animated> | ||||
|           <el-row> | ||||
|             <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-10px"> | ||||
|               <div class="flex items-center"> | ||||
|                 <Icon :icon="item.icon" class="mr-10px" /> | ||||
|                 <el-link type="default" :underline="false" :href="item.url"> | ||||
|                   {{ item.name }} | ||||
|                 </el-link> | ||||
|               </div> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-skeleton> | ||||
|       </el-card> | ||||
|       <el-card shadow="never" class="mt-10px"> | ||||
|         <template #header> | ||||
|           <div class="flex justify-between h-3"> | ||||
|             <span>{{ t('workplace.notice') }}</span> | ||||
|             <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link> | ||||
|           </div> | ||||
|         </template> | ||||
|         <el-skeleton :loading="loading" animated> | ||||
|           <div v-for="(item, index) in notice" :key="`dynamics-${index}`"> | ||||
|             <div class="flex items-center"> | ||||
|               <img :src="avatar" alt="" class="w-35px h-35px rounded-[50%] mr-20px" /> | ||||
|               <div> | ||||
|                 <div class="text-14px"> | ||||
|                   <Highlight :keys="item.keys.map((v) => t(v))"> | ||||
|                     {{ item.type }} : {{ item.title }} | ||||
|                   </Highlight> | ||||
|                 </div> | ||||
|                 <div class="mt-15px text-12px text-gray-400"> | ||||
|                   {{ formatTime(item.date, 'yyyy-MM-dd') }} | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|             <el-divider /> | ||||
|           </div> | ||||
|         </el-skeleton> | ||||
|       </el-card> | ||||
|     </el-col> | ||||
|   </el-row> | ||||
| </template> | ||||
|   | ||||
| @@ -1,133 +1,3 @@ | ||||
| <script setup lang="ts"> | ||||
| import { ref, reactive } from 'vue' | ||||
| import { set } from 'lodash-es' | ||||
| import { EChartsOption } from 'echarts' | ||||
| import { Echart } from '@/components/Echart' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| import { CountTo } from '@/components/CountTo' | ||||
| import type { AnalysisTotalTypes } from './types' | ||||
| import { useDesign } from '@/hooks/web/useDesign' | ||||
| import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus' | ||||
| import { pieOptions, barOptions, lineOptions } from './echarts-data' | ||||
|  | ||||
| const { t } = useI18n() | ||||
| const loading = ref(true) | ||||
| const { getPrefixCls } = useDesign() | ||||
| const prefixCls = getPrefixCls('panel') | ||||
| const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption | ||||
|  | ||||
| let totalState = reactive<AnalysisTotalTypes>({ | ||||
|   users: 0, | ||||
|   messages: 0, | ||||
|   moneys: 0, | ||||
|   shoppings: 0 | ||||
| }) | ||||
|  | ||||
| const getCount = async () => { | ||||
|   const data = { | ||||
|     users: 102400, | ||||
|     messages: 81212, | ||||
|     moneys: 9280, | ||||
|     shoppings: 13600 | ||||
|   } | ||||
|   totalState = Object.assign(totalState, data) | ||||
| } | ||||
|  | ||||
| // 用户来源 | ||||
| const getUserAccessSource = async () => { | ||||
|   const data = [ | ||||
|     { value: 335, name: 'analysis.directAccess' }, | ||||
|     { value: 310, name: 'analysis.mailMarketing' }, | ||||
|     { value: 234, name: 'analysis.allianceAdvertising' }, | ||||
|     { value: 135, name: 'analysis.videoAdvertising' }, | ||||
|     { value: 1548, name: 'analysis.searchEngines' } | ||||
|   ] | ||||
|   set( | ||||
|     pieOptionsData, | ||||
|     'legend.data', | ||||
|     data.map((v) => t(v.name)) | ||||
|   ) | ||||
|   set(pieOptionsData, 'series.data', data) | ||||
| } | ||||
| const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption | ||||
|  | ||||
| // 周活跃量 | ||||
| const getWeeklyUserActivity = async () => { | ||||
|   const data = [ | ||||
|     { value: 13253, name: 'analysis.monday' }, | ||||
|     { value: 34235, name: 'analysis.tuesday' }, | ||||
|     { value: 26321, name: 'analysis.wednesday' }, | ||||
|     { value: 12340, name: 'analysis.thursday' }, | ||||
|     { value: 24643, name: 'analysis.friday' }, | ||||
|     { value: 1322, name: 'analysis.saturday' }, | ||||
|     { value: 1324, name: 'analysis.sunday' } | ||||
|   ] | ||||
|   set( | ||||
|     barOptionsData, | ||||
|     'xAxis.data', | ||||
|     data.map((v) => t(v.name)) | ||||
|   ) | ||||
|   set(barOptionsData, 'series', [ | ||||
|     { | ||||
|       name: t('analysis.activeQuantity'), | ||||
|       data: data.map((v) => v.value), | ||||
|       type: 'bar' | ||||
|     } | ||||
|   ]) | ||||
| } | ||||
|  | ||||
| const lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption | ||||
|  | ||||
| // 每月销售总额 | ||||
| const getMonthlySales = async () => { | ||||
|   const data = [ | ||||
|     { estimate: 100, actual: 120, name: 'analysis.january' }, | ||||
|     { estimate: 120, actual: 82, name: 'analysis.february' }, | ||||
|     { estimate: 161, actual: 91, name: 'analysis.march' }, | ||||
|     { estimate: 134, actual: 154, name: 'analysis.april' }, | ||||
|     { estimate: 105, actual: 162, name: 'analysis.may' }, | ||||
|     { estimate: 160, actual: 140, name: 'analysis.june' }, | ||||
|     { estimate: 165, actual: 145, name: 'analysis.july' }, | ||||
|     { estimate: 114, actual: 250, name: 'analysis.august' }, | ||||
|     { estimate: 163, actual: 134, name: 'analysis.september' }, | ||||
|     { estimate: 185, actual: 56, name: 'analysis.october' }, | ||||
|     { estimate: 118, actual: 99, name: 'analysis.november' }, | ||||
|     { estimate: 123, actual: 123, name: 'analysis.december' } | ||||
|   ] | ||||
|   set( | ||||
|     lineOptionsData, | ||||
|     'xAxis.data', | ||||
|     data.map((v) => t(v.name)) | ||||
|   ) | ||||
|   set(lineOptionsData, 'series', [ | ||||
|     { | ||||
|       name: t('analysis.estimate'), | ||||
|       smooth: true, | ||||
|       type: 'line', | ||||
|       data: data.map((v) => v.estimate), | ||||
|       animationDuration: 2800, | ||||
|       animationEasing: 'cubicInOut' | ||||
|     }, | ||||
|     { | ||||
|       name: t('analysis.actual'), | ||||
|       smooth: true, | ||||
|       type: 'line', | ||||
|       itemStyle: {}, | ||||
|       data: data.map((v) => v.actual), | ||||
|       animationDuration: 2800, | ||||
|       animationEasing: 'quadraticOut' | ||||
|     } | ||||
|   ]) | ||||
| } | ||||
|  | ||||
| const getAllApi = async () => { | ||||
|   await Promise.all([getCount(), getUserAccessSource(), getWeeklyUserActivity(), getMonthlySales()]) | ||||
|   loading.value = false | ||||
| } | ||||
|  | ||||
| getAllApi() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <el-row :gutter="20" justify="space-between" :class="prefixCls"> | ||||
|     <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24"> | ||||
| @@ -270,6 +140,136 @@ getAllApi() | ||||
|     </el-col> | ||||
|   </el-row> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { ref, reactive } from 'vue' | ||||
| import { set } from 'lodash-es' | ||||
| import { EChartsOption } from 'echarts' | ||||
| import { Echart } from '@/components/Echart' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| import { CountTo } from '@/components/CountTo' | ||||
| import type { AnalysisTotalTypes } from './types' | ||||
| import { useDesign } from '@/hooks/web/useDesign' | ||||
| import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus' | ||||
| import { pieOptions, barOptions, lineOptions } from './echarts-data' | ||||
|  | ||||
| const { t } = useI18n() | ||||
| const loading = ref(true) | ||||
| const { getPrefixCls } = useDesign() | ||||
| const prefixCls = getPrefixCls('panel') | ||||
| const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption | ||||
|  | ||||
| let totalState = reactive<AnalysisTotalTypes>({ | ||||
|   users: 0, | ||||
|   messages: 0, | ||||
|   moneys: 0, | ||||
|   shoppings: 0 | ||||
| }) | ||||
|  | ||||
| const getCount = async () => { | ||||
|   const data = { | ||||
|     users: 102400, | ||||
|     messages: 81212, | ||||
|     moneys: 9280, | ||||
|     shoppings: 13600 | ||||
|   } | ||||
|   totalState = Object.assign(totalState, data) | ||||
| } | ||||
|  | ||||
| // 用户来源 | ||||
| const getUserAccessSource = async () => { | ||||
|   const data = [ | ||||
|     { value: 335, name: 'analysis.directAccess' }, | ||||
|     { value: 310, name: 'analysis.mailMarketing' }, | ||||
|     { value: 234, name: 'analysis.allianceAdvertising' }, | ||||
|     { value: 135, name: 'analysis.videoAdvertising' }, | ||||
|     { value: 1548, name: 'analysis.searchEngines' } | ||||
|   ] | ||||
|   set( | ||||
|     pieOptionsData, | ||||
|     'legend.data', | ||||
|     data.map((v) => t(v.name)) | ||||
|   ) | ||||
|   set(pieOptionsData, 'series.data', data) | ||||
| } | ||||
| const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption | ||||
|  | ||||
| // 周活跃量 | ||||
| const getWeeklyUserActivity = async () => { | ||||
|   const data = [ | ||||
|     { value: 13253, name: 'analysis.monday' }, | ||||
|     { value: 34235, name: 'analysis.tuesday' }, | ||||
|     { value: 26321, name: 'analysis.wednesday' }, | ||||
|     { value: 12340, name: 'analysis.thursday' }, | ||||
|     { value: 24643, name: 'analysis.friday' }, | ||||
|     { value: 1322, name: 'analysis.saturday' }, | ||||
|     { value: 1324, name: 'analysis.sunday' } | ||||
|   ] | ||||
|   set( | ||||
|     barOptionsData, | ||||
|     'xAxis.data', | ||||
|     data.map((v) => t(v.name)) | ||||
|   ) | ||||
|   set(barOptionsData, 'series', [ | ||||
|     { | ||||
|       name: t('analysis.activeQuantity'), | ||||
|       data: data.map((v) => v.value), | ||||
|       type: 'bar' | ||||
|     } | ||||
|   ]) | ||||
| } | ||||
|  | ||||
| const lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption | ||||
|  | ||||
| // 每月销售总额 | ||||
| const getMonthlySales = async () => { | ||||
|   const data = [ | ||||
|     { estimate: 100, actual: 120, name: 'analysis.january' }, | ||||
|     { estimate: 120, actual: 82, name: 'analysis.february' }, | ||||
|     { estimate: 161, actual: 91, name: 'analysis.march' }, | ||||
|     { estimate: 134, actual: 154, name: 'analysis.april' }, | ||||
|     { estimate: 105, actual: 162, name: 'analysis.may' }, | ||||
|     { estimate: 160, actual: 140, name: 'analysis.june' }, | ||||
|     { estimate: 165, actual: 145, name: 'analysis.july' }, | ||||
|     { estimate: 114, actual: 250, name: 'analysis.august' }, | ||||
|     { estimate: 163, actual: 134, name: 'analysis.september' }, | ||||
|     { estimate: 185, actual: 56, name: 'analysis.october' }, | ||||
|     { estimate: 118, actual: 99, name: 'analysis.november' }, | ||||
|     { estimate: 123, actual: 123, name: 'analysis.december' } | ||||
|   ] | ||||
|   set( | ||||
|     lineOptionsData, | ||||
|     'xAxis.data', | ||||
|     data.map((v) => t(v.name)) | ||||
|   ) | ||||
|   set(lineOptionsData, 'series', [ | ||||
|     { | ||||
|       name: t('analysis.estimate'), | ||||
|       smooth: true, | ||||
|       type: 'line', | ||||
|       data: data.map((v) => v.estimate), | ||||
|       animationDuration: 2800, | ||||
|       animationEasing: 'cubicInOut' | ||||
|     }, | ||||
|     { | ||||
|       name: t('analysis.actual'), | ||||
|       smooth: true, | ||||
|       type: 'line', | ||||
|       itemStyle: {}, | ||||
|       data: data.map((v) => v.actual), | ||||
|       animationDuration: 2800, | ||||
|       animationEasing: 'quadraticOut' | ||||
|     } | ||||
|   ]) | ||||
| } | ||||
|  | ||||
| const getAllApi = async () => { | ||||
|   await Promise.all([getCount(), getUserAccessSource(), getWeeklyUserActivity(), getMonthlySales()]) | ||||
|   loading.value = false | ||||
| } | ||||
|  | ||||
| getAllApi() | ||||
| </script> | ||||
|  | ||||
| <style lang="less" scoped> | ||||
| @prefix-cls: ~'@{namespace}-panel'; | ||||
|  | ||||
|   | ||||
| @@ -1,21 +1,3 @@ | ||||
| <script setup lang="ts"> | ||||
| import { LoginForm, MobileForm, RegisterForm, QrCodeForm } from './components' | ||||
| import { ThemeSwitch } from '@/components/ThemeSwitch' | ||||
| import { LocaleDropdown } from '@/components/LocaleDropdown' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| import { underlineToHump } from '@/utils' | ||||
| import { useAppStore } from '@/store/modules/app' | ||||
| import { useDesign } from '@/hooks/web/useDesign' | ||||
|  | ||||
| const { t } = useI18n() | ||||
|  | ||||
| const { getPrefixCls } = useDesign() | ||||
|  | ||||
| const prefixCls = getPrefixCls('login') | ||||
|  | ||||
| const appStore = useAppStore() | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div | ||||
|     :class="prefixCls" | ||||
| @@ -76,6 +58,23 @@ const appStore = useAppStore() | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { LoginForm, MobileForm, RegisterForm, QrCodeForm } from './components' | ||||
| import { ThemeSwitch } from '@/components/ThemeSwitch' | ||||
| import { LocaleDropdown } from '@/components/LocaleDropdown' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| import { underlineToHump } from '@/utils' | ||||
| import { useAppStore } from '@/store/modules/app' | ||||
| import { useDesign } from '@/hooks/web/useDesign' | ||||
|  | ||||
| const { t } = useI18n() | ||||
|  | ||||
| const { getPrefixCls } = useDesign() | ||||
|  | ||||
| const prefixCls = getPrefixCls('login') | ||||
|  | ||||
| const appStore = useAppStore() | ||||
| </script> | ||||
|  | ||||
| <style lang="less" scoped> | ||||
| @prefix-cls: ~'@{namespace}-login'; | ||||
|   | ||||
| @@ -1,3 +1,141 @@ | ||||
| <template> | ||||
|   <el-form | ||||
|     :model="loginData.loginForm" | ||||
|     :rules="LoginRules" | ||||
|     label-position="top" | ||||
|     class="login-form" | ||||
|     label-width="120px" | ||||
|     size="large" | ||||
|     v-show="getShow" | ||||
|     ref="formLogin" | ||||
|   > | ||||
|     <el-row style="maring-left: -10px; maring-right: -10px"> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <LoginFormTitle style="width: 100%" /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="tenantName"> | ||||
|           <el-input | ||||
|             type="text" | ||||
|             v-model="loginData.loginForm.tenantName" | ||||
|             :placeholder="t('login.tenantNamePlaceholder')" | ||||
|             :prefix-icon="iconHouse" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="username"> | ||||
|           <el-input | ||||
|             v-model="loginData.loginForm.username" | ||||
|             :placeholder="t('login.usernamePlaceholder')" | ||||
|             :prefix-icon="iconAvatar" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="password"> | ||||
|           <el-input | ||||
|             v-model="loginData.loginForm.password" | ||||
|             type="password" | ||||
|             :placeholder="t('login.passwordPlaceholder')" | ||||
|             show-password | ||||
|             @keyup.enter="getCode()" | ||||
|             :prefix-icon="iconLock" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col | ||||
|         :span="24" | ||||
|         style="padding-left: 10px; padding-right: 10px; margin-top: -20px; margin-bottom: -20px" | ||||
|       > | ||||
|         <el-form-item> | ||||
|           <el-row justify="space-between" style="width: 100%"> | ||||
|             <el-col :span="6"> | ||||
|               <el-checkbox v-model="loginData.loginForm.rememberMe"> | ||||
|                 {{ t('login.remember') }} | ||||
|               </el-checkbox> | ||||
|             </el-col> | ||||
|             <el-col :span="12" :offset="6"> | ||||
|               <el-link type="primary" style="float: right">{{ t('login.forgetPassword') }}</el-link> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="getCode()"> | ||||
|             {{ t('login.login') }} | ||||
|           </el-button> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <Verify | ||||
|         ref="verify" | ||||
|         mode="pop" | ||||
|         :captchaType="captchaType" | ||||
|         :imgSize="{ width: '400px', height: '200px' }" | ||||
|         @success="handleLogin" | ||||
|       /> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <el-row justify="space-between" style="width: 100%" :gutter="5"> | ||||
|             <el-col :span="8"> | ||||
|               <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.MOBILE)"> | ||||
|                 {{ t('login.btnMobile') }} | ||||
|               </el-button> | ||||
|             </el-col> | ||||
|             <el-col :span="8"> | ||||
|               <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.QR_CODE)"> | ||||
|                 {{ t('login.btnQRCode') }} | ||||
|               </el-button> | ||||
|             </el-col> | ||||
|             <el-col :span="8"> | ||||
|               <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.REGISTER)"> | ||||
|                 {{ t('login.btnRegister') }} | ||||
|               </el-button> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <div class="flex justify-between w-[100%]"> | ||||
|             <Icon | ||||
|               icon="ant-design:github-filled" | ||||
|               :size="iconSize" | ||||
|               class="cursor-pointer anticon" | ||||
|               :color="iconColor" | ||||
|               @click="doSocialLogin('github')" | ||||
|             /> | ||||
|             <Icon | ||||
|               icon="ant-design:wechat-filled" | ||||
|               :size="iconSize" | ||||
|               class="cursor-pointer anticon" | ||||
|               :color="iconColor" | ||||
|               @click="doSocialLogin('wechat')" | ||||
|             /> | ||||
|             <Icon | ||||
|               icon="ant-design:alipay-circle-filled" | ||||
|               :size="iconSize" | ||||
|               :color="iconColor" | ||||
|               class="cursor-pointer anticon" | ||||
|               @click="doSocialLogin('alipay')" | ||||
|             /> | ||||
|             <Icon | ||||
|               icon="ant-design:dingtalk-circle-filled" | ||||
|               :size="iconSize" | ||||
|               :color="iconColor" | ||||
|               class="cursor-pointer anticon" | ||||
|               @click="doSocialLogin('dingtalk')" | ||||
|             /> | ||||
|           </div> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|   </el-form> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { useIcon } from '@/hooks/web/useIcon' | ||||
| import LoginFormTitle from './LoginFormTitle.vue' | ||||
| @@ -153,144 +291,7 @@ onMounted(() => { | ||||
|   getCookie() | ||||
| }) | ||||
| </script> | ||||
| <template> | ||||
|   <el-form | ||||
|     :model="loginData.loginForm" | ||||
|     :rules="LoginRules" | ||||
|     label-position="top" | ||||
|     class="login-form" | ||||
|     label-width="120px" | ||||
|     size="large" | ||||
|     v-show="getShow" | ||||
|     ref="formLogin" | ||||
|   > | ||||
|     <el-row style="maring-left: -10px; maring-right: -10px"> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <LoginFormTitle style="width: 100%" /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="tenantName"> | ||||
|           <el-input | ||||
|             type="text" | ||||
|             v-model="loginData.loginForm.tenantName" | ||||
|             :placeholder="t('login.tenantNamePlaceholder')" | ||||
|             :prefix-icon="iconHouse" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="username"> | ||||
|           <el-input | ||||
|             v-model="loginData.loginForm.username" | ||||
|             :placeholder="t('login.usernamePlaceholder')" | ||||
|             :prefix-icon="iconAvatar" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="password"> | ||||
|           <el-input | ||||
|             v-model="loginData.loginForm.password" | ||||
|             type="password" | ||||
|             :placeholder="t('login.passwordPlaceholder')" | ||||
|             show-password | ||||
|             @keyup.enter="getCode()" | ||||
|             :prefix-icon="iconLock" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col | ||||
|         :span="24" | ||||
|         style="padding-left: 10px; padding-right: 10px; margin-top: -20px; margin-bottom: -20px" | ||||
|       > | ||||
|         <el-form-item> | ||||
|           <el-row justify="space-between" style="width: 100%"> | ||||
|             <el-col :span="6"> | ||||
|               <el-checkbox v-model="loginData.loginForm.rememberMe"> | ||||
|                 {{ t('login.remember') }} | ||||
|               </el-checkbox> | ||||
|             </el-col> | ||||
|             <el-col :span="12" :offset="6"> | ||||
|               <el-link type="primary" style="float: right">{{ t('login.forgetPassword') }}</el-link> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="getCode()"> | ||||
|             {{ t('login.login') }} | ||||
|           </el-button> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <Verify | ||||
|         ref="verify" | ||||
|         mode="pop" | ||||
|         :captchaType="captchaType" | ||||
|         :imgSize="{ width: '400px', height: '200px' }" | ||||
|         @success="handleLogin" | ||||
|       /> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <el-row justify="space-between" style="width: 100%" :gutter="5"> | ||||
|             <el-col :span="8"> | ||||
|               <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.MOBILE)"> | ||||
|                 {{ t('login.btnMobile') }} | ||||
|               </el-button> | ||||
|             </el-col> | ||||
|             <el-col :span="8"> | ||||
|               <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.QR_CODE)"> | ||||
|                 {{ t('login.btnQRCode') }} | ||||
|               </el-button> | ||||
|             </el-col> | ||||
|             <el-col :span="8"> | ||||
|               <el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.REGISTER)"> | ||||
|                 {{ t('login.btnRegister') }} | ||||
|               </el-button> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <div class="flex justify-between w-[100%]"> | ||||
|             <Icon | ||||
|               icon="ant-design:github-filled" | ||||
|               :size="iconSize" | ||||
|               class="cursor-pointer anticon" | ||||
|               :color="iconColor" | ||||
|               @click="doSocialLogin('github')" | ||||
|             /> | ||||
|             <Icon | ||||
|               icon="ant-design:wechat-filled" | ||||
|               :size="iconSize" | ||||
|               class="cursor-pointer anticon" | ||||
|               :color="iconColor" | ||||
|               @click="doSocialLogin('wechat')" | ||||
|             /> | ||||
|             <Icon | ||||
|               icon="ant-design:alipay-circle-filled" | ||||
|               :size="iconSize" | ||||
|               :color="iconColor" | ||||
|               class="cursor-pointer anticon" | ||||
|               @click="doSocialLogin('alipay')" | ||||
|             /> | ||||
|             <Icon | ||||
|               icon="ant-design:dingtalk-circle-filled" | ||||
|               :size="iconSize" | ||||
|               :color="iconColor" | ||||
|               class="cursor-pointer anticon" | ||||
|               @click="doSocialLogin('dingtalk')" | ||||
|             /> | ||||
|           </div> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|   </el-form> | ||||
| </template> | ||||
|  | ||||
| <style lang="less" scoped> | ||||
| :deep(.anticon) { | ||||
|   &:hover { | ||||
|   | ||||
| @@ -1,3 +1,8 @@ | ||||
| <template> | ||||
|   <h2 class="mb-3 text-2xl font-bold text-center xl:text-3xl enter-x xl:text-center"> | ||||
|     {{ getFormTitle }} | ||||
|   </h2> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { computed, unref } from 'vue' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| @@ -18,8 +23,3 @@ const getFormTitle = computed(() => { | ||||
|   return titleObj[unref(getLoginState)] | ||||
| }) | ||||
| </script> | ||||
| <template> | ||||
|   <h2 class="mb-3 text-2xl font-bold text-center xl:text-3xl enter-x xl:text-center"> | ||||
|     {{ getFormTitle }} | ||||
|   </h2> | ||||
| </template> | ||||
|   | ||||
| @@ -1,3 +1,89 @@ | ||||
| <template> | ||||
|   <el-form | ||||
|     :model="loginData.loginForm" | ||||
|     :rules="rules" | ||||
|     label-position="top" | ||||
|     class="login-form" | ||||
|     label-width="120px" | ||||
|     size="large" | ||||
|     v-show="getShow" | ||||
|     ref="formSmsLogin" | ||||
|   > | ||||
|     <el-row style="margin-left: -10px; margin-right: -10px"> | ||||
|       <!-- 租户名 --> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <LoginFormTitle style="width: 100%" /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="tenantName"> | ||||
|           <el-input | ||||
|             type="text" | ||||
|             v-model="loginData.loginForm.tenantName" | ||||
|             :placeholder="t('login.tenantNamePlaceholder')" | ||||
|             :prefix-icon="iconHouse" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <!-- 手机号 --> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="mobileNumber"> | ||||
|           <el-input | ||||
|             v-model="loginData.loginForm.mobileNumber" | ||||
|             :placeholder="t('login.mobileNumberPlaceholder')" | ||||
|             :prefix-icon="iconCellphone" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <!-- 验证码 --> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="code"> | ||||
|           <el-row justify="space-between" style="width: 100%" :gutter="5"> | ||||
|             <el-col :span="24"> | ||||
|               <el-input | ||||
|                 v-model="loginData.loginForm.code" | ||||
|                 :placeholder="t('login.codePlaceholder')" | ||||
|                 :prefix-icon="iconCircleCheck" | ||||
|               > | ||||
|                 <!-- <el-button class="w-[100%]"> --> | ||||
|                 <template #append> | ||||
|                   <span | ||||
|                     v-if="mobileCodeTimer <= 0" | ||||
|                     @click="getSmsCode" | ||||
|                     class="getMobileCode" | ||||
|                     style="cursor: pointer" | ||||
|                   > | ||||
|                     {{ t('login.getSmsCode') }} | ||||
|                   </span> | ||||
|                   <span v-if="mobileCodeTimer > 0" class="getMobileCode" style="cursor: pointer"> | ||||
|                     {{ mobileCodeTimer }}秒后可重新获取 | ||||
|                   </span> | ||||
|                 </template> | ||||
|               </el-input> | ||||
|               <!-- </el-button> --> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <!-- 登录按钮 / 返回按钮 --> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="signIn"> | ||||
|             {{ t('login.login') }} | ||||
|           </el-button> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <el-button :loading="loginLoading" class="w-[100%]" @click="handleBackLogin"> | ||||
|             {{ t('login.backLogin') }} | ||||
|           </el-button> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|   </el-form> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { useIcon } from '@/hooks/web/useIcon' | ||||
| import { reactive, ref, unref, watch, computed } from 'vue' | ||||
| @@ -111,92 +197,7 @@ const signIn = async () => { | ||||
|     }) | ||||
| } | ||||
| </script> | ||||
| <template> | ||||
|   <el-form | ||||
|     :model="loginData.loginForm" | ||||
|     :rules="rules" | ||||
|     label-position="top" | ||||
|     class="login-form" | ||||
|     label-width="120px" | ||||
|     size="large" | ||||
|     v-show="getShow" | ||||
|     ref="formSmsLogin" | ||||
|   > | ||||
|     <el-row style="margin-left: -10px; margin-right: -10px"> | ||||
|       <!-- 租户名 --> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <LoginFormTitle style="width: 100%" /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="tenantName"> | ||||
|           <el-input | ||||
|             type="text" | ||||
|             v-model="loginData.loginForm.tenantName" | ||||
|             :placeholder="t('login.tenantNamePlaceholder')" | ||||
|             :prefix-icon="iconHouse" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <!-- 手机号 --> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="mobileNumber"> | ||||
|           <el-input | ||||
|             v-model="loginData.loginForm.mobileNumber" | ||||
|             :placeholder="t('login.mobileNumberPlaceholder')" | ||||
|             :prefix-icon="iconCellphone" | ||||
|           /> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <!-- 验证码 --> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item prop="code"> | ||||
|           <el-row justify="space-between" style="width: 100%" :gutter="5"> | ||||
|             <el-col :span="24"> | ||||
|               <el-input | ||||
|                 v-model="loginData.loginForm.code" | ||||
|                 :placeholder="t('login.codePlaceholder')" | ||||
|                 :prefix-icon="iconCircleCheck" | ||||
|               > | ||||
|                 <!-- <el-button class="w-[100%]"> --> | ||||
|                 <template #append> | ||||
|                   <span | ||||
|                     v-if="mobileCodeTimer <= 0" | ||||
|                     @click="getSmsCode" | ||||
|                     class="getMobileCode" | ||||
|                     style="cursor: pointer" | ||||
|                   > | ||||
|                     {{ t('login.getSmsCode') }} | ||||
|                   </span> | ||||
|                   <span v-if="mobileCodeTimer > 0" class="getMobileCode" style="cursor: pointer"> | ||||
|                     {{ mobileCodeTimer }}秒后可重新获取 | ||||
|                   </span> | ||||
|                 </template> | ||||
|               </el-input> | ||||
|               <!-- </el-button> --> | ||||
|             </el-col> | ||||
|           </el-row> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <!-- 登录按钮 / 返回按钮 --> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="signIn"> | ||||
|             {{ t('login.login') }} | ||||
|           </el-button> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|       <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
|         <el-form-item> | ||||
|           <el-button :loading="loginLoading" class="w-[100%]" @click="handleBackLogin"> | ||||
|             {{ t('login.backLogin') }} | ||||
|           </el-button> | ||||
|         </el-form-item> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|   </el-form> | ||||
| </template> | ||||
|  | ||||
| <style lang="less" scoped> | ||||
| :deep(.anticon) { | ||||
|   &:hover { | ||||
|   | ||||
| @@ -1,17 +1,3 @@ | ||||
| <script setup lang="ts"> | ||||
| import { computed, unref } from 'vue' | ||||
| import { ElRow, ElCol, ElCard, ElDivider } from 'element-plus' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| import { useLoginState, LoginStateEnum } from './useLogin' | ||||
| import LoginFormTitle from './LoginFormTitle.vue' | ||||
| import { Qrcode } from '@/components/Qrcode' | ||||
| import logoImg from '@/assets/imgs/logo.png' | ||||
|  | ||||
| const { t } = useI18n() | ||||
| const { handleBackLogin, getLoginState } = useLoginState() | ||||
| const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE) | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <el-row v-show="getShow" style="maring-left: -10px; maring-right: -10px"> | ||||
|     <el-col :span="24" style="padding-left: 10px; padding-right: 10px"> | ||||
| @@ -32,3 +18,16 @@ const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE) | ||||
|     </el-col> | ||||
|   </el-row> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { computed, unref } from 'vue' | ||||
| import { ElRow, ElCol, ElCard, ElDivider } from 'element-plus' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| import { useLoginState, LoginStateEnum } from './useLogin' | ||||
| import LoginFormTitle from './LoginFormTitle.vue' | ||||
| import { Qrcode } from '@/components/Qrcode' | ||||
| import logoImg from '@/assets/imgs/logo.png' | ||||
|  | ||||
| const { t } = useI18n() | ||||
| const { handleBackLogin, getLoginState } = useLoginState() | ||||
| const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE) | ||||
| </script> | ||||
|   | ||||
| @@ -1,3 +1,39 @@ | ||||
| <template> | ||||
|   <Form | ||||
|     :schema="schema" | ||||
|     :rules="rules" | ||||
|     label-position="top" | ||||
|     hide-required-asterisk | ||||
|     size="large" | ||||
|     v-show="getShow" | ||||
|     class="dark:(border-1 border-[var(--el-border-color)] border-solid)" | ||||
|     @register="register" | ||||
|   > | ||||
|     <template #title> | ||||
|       <LoginFormTitle style="width: 100%" /> | ||||
|     </template> | ||||
|  | ||||
|     <template #code="form"> | ||||
|       <div class="w-[100%] flex"> | ||||
|         <el-input v-model="form['code']" :placeholder="t('login.codePlaceholder')" /> | ||||
|       </div> | ||||
|     </template> | ||||
|  | ||||
|     <template #register> | ||||
|       <div class="w-[100%]"> | ||||
|         <el-button type="primary" class="w-[100%]" :loading="loading" @click="loginRegister"> | ||||
|           {{ t('login.register') }} | ||||
|         </el-button> | ||||
|       </div> | ||||
|       <div class="w-[100%] mt-15px"> | ||||
|         <el-button class="w-[100%]" @click="handleBackLogin"> | ||||
|           {{ t('login.hasUser') }} | ||||
|         </el-button> | ||||
|       </div> | ||||
|     </template> | ||||
|   </Form> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { Form } from '@/components/Form' | ||||
| import { computed, reactive, ref, unref } from 'vue' | ||||
| @@ -104,39 +140,3 @@ const loginRegister = async () => { | ||||
|   }) | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <Form | ||||
|     :schema="schema" | ||||
|     :rules="rules" | ||||
|     label-position="top" | ||||
|     hide-required-asterisk | ||||
|     size="large" | ||||
|     v-show="getShow" | ||||
|     class="dark:(border-1 border-[var(--el-border-color)] border-solid)" | ||||
|     @register="register" | ||||
|   > | ||||
|     <template #title> | ||||
|       <LoginFormTitle style="width: 100%" /> | ||||
|     </template> | ||||
|  | ||||
|     <template #code="form"> | ||||
|       <div class="w-[100%] flex"> | ||||
|         <el-input v-model="form['code']" :placeholder="t('login.codePlaceholder')" /> | ||||
|       </div> | ||||
|     </template> | ||||
|  | ||||
|     <template #register> | ||||
|       <div class="w-[100%]"> | ||||
|         <el-button type="primary" class="w-[100%]" :loading="loading" @click="loginRegister"> | ||||
|           {{ t('login.register') }} | ||||
|         </el-button> | ||||
|       </div> | ||||
|       <div class="w-[100%] mt-15px"> | ||||
|         <el-button class="w-[100%]" @click="handleBackLogin"> | ||||
|           {{ t('login.hasUser') }} | ||||
|         </el-button> | ||||
|       </div> | ||||
|     </template> | ||||
|   </Form> | ||||
| </template> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 xingyu4j
					xingyu4j