任务大厅

main
zhufu 2024-11-19 16:52:09 +08:00
parent 0038e78bb8
commit 95f6dde379
50 changed files with 1501 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
public/taskhall/header.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/taskhall/light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
public/taskhall/podium.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

47
src/api/demo/taskhall.ts Normal file
View File

@ -0,0 +1,47 @@
import { defHttp } from '@/utils/http/axios';
enum Api {
// 任务区
GetTaskList = '/api/InsTaskHall/GetTaskList',
// 根据任务id获取分组任务
GetgrouptaskList = '/api/InsTaskHall/GetgrouptaskList',
// 领取任务
ReciveTask = '/api/InsTaskHall/ReciveTask',
// 已完成任务
GetCompleteTaskList = '/api/InsTaskHall/GetCompleteTaskList',
// 最佳员工排行
GetRankingList = '/api/InsTaskHall/GetRankingList',
// 组排名
GetGroupRankingList = '/api/InsTaskHall/GetGroupRankingList',
// 在线办理
GetTaskingList = '/api/InsTaskHall/GetTaskingList',
}
export const GetTaskList = () => defHttp.get({ url: Api.GetTaskList });
export const GetgrouptaskList = (params:{ id: string }) => {
return defHttp.get({
url: Api.GetgrouptaskList,
params,
})
};
export const ReciveTask = ( data: string[] ) => {
return defHttp.post({
url: Api.ReciveTask,
data,
})
}
export const GetCompleteTaskList = () => defHttp.get({ url: Api.GetCompleteTaskList });
export const GetRankingList = (params:{ flag: string }) => {
return defHttp.get({
url: Api.GetRankingList,
params,
})
};
export const GetGroupRankingList = () => defHttp.get({ url: Api.GetGroupRankingList });
export const GetTaskingList = () => defHttp.get({ url: Api.GetTaskingList });

View File

@ -90,4 +90,28 @@ ul {
color: rgba(0, 0, 0, 0.8) !important;
background: rgba(0, 0, 0, 0.01) !important;
}
@font-face {
font-family: 'HuXiaoBo-NanShen'; /* 自定义字体名称 */
src: url('/public/taskhall/fonts/HuXiaoBo-NanShen.otf') format('opentype');
font-weight: normal; /* 可选:指定字体的粗细 */
font-style: normal; /* 可选:指定字体样式 */
}
@font-face {
font-family: 'AlibabaPuHuiTiR'; /* 自定义字体名称 */
src: url('/public/taskhall/fonts/AlibabaPuHuiTiRegular.ttf') format('truetype');
font-weight: normal; /* 可选:指定字体的粗细 */
font-style: normal; /* 可选:指定字体样式 */
}
@font-face {
font-family: 'AlibabaPuHuiTiM'; /* 自定义字体名称 */
src: url('/public/taskhall/fonts/AlibabaPuHuiTiMedium.ttf') format('truetype');
font-weight: normal; /* 可选:指定字体的粗细 */
font-style: normal; /* 可选:指定字体样式 */
}
@font-face {
font-family: 'DINPro'; /* 自定义字体名称 */
src: url('/public/taskhall/fonts/DINPro-Medium.ttf') format('truetype');
font-weight: normal; /* 可选:指定字体的粗细 */
font-style: normal; /* 可选:指定字体样式 */
}

View File

@ -0,0 +1,13 @@
import type { AppRouteModule } from '@/router/types';
const taskhall: AppRouteModule = {
path: '/TaskHall',
name: 'TaskHall',
component: () => import('@/views/demo/taskhall/index.vue'),
meta: {
title: "任务大厅",
},
};
export default taskhall;

View File

@ -0,0 +1,265 @@
<template>
<div class="sub_title" style="width: 472px;display: flex;justify-content: space-between;padding-top: 0px;position: relative;z-index: 2;margin-bottom: 0px;">
<div style="padding-top: 3px;">最佳员工</div>
<div style="display: flex;">
<div :class="`handoff-button ${handoffButton == 'week'? 'handoff-button-active': ''}`" style="margin-right: 3px;" @click="changeRankingType('week')"></div>
<div :class="`handoff-button ${handoffButton == 'month'? 'handoff-button-active': ''}`" style="margin-right: 3px;" @click="changeRankingType('month')"></div>
<div :class="`handoff-button ${handoffButton == 'total'? 'handoff-button-active': ''}`" @click="changeRankingType('total')"></div>
</div>
</div>
<div class="best-employee">
<div class="podium">
<div class="first-place" v-if="firstPlace">
<img :src="`${firstPlace.HeadIcon? `${VITE_GLOB_UPLOAD_URL}/${firstPlace.HeadIcon}`: imageError}`" class="user-image"/>
<div class="first-mark"></div>
<div class="user-name">{{firstPlace.Name}}</div>
<div class="gap">{{`+${firstPlace.count}`}}</div>
</div>
<div class="second-place" v-if="secondPlace">
<img :src="`${secondPlace.HeadIcon? `${VITE_GLOB_UPLOAD_URL}/${secondPlace.HeadIcon}`: imageError}`" class="user-image" />
<div class="second-mark"></div>
<span class="user-name">{{secondPlace.Name}}</span>
<div class="gap">{{`+${secondPlace.count}`}}</div>
</div>
<div class="third-place" v-if="thirdPlace">
<img :src="`${thirdPlace.HeadIcon? `${VITE_GLOB_UPLOAD_URL}/${thirdPlace.HeadIcon}`: imageError}`" class="user-image" />
<div class="third-mark"></div>
<span class="user-name">{{thirdPlace.Name}}</span>
<div class="gap">{{`+${thirdPlace.count}`}}</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, defineProps, watch } from "vue"
import { GetRankingList } from '@/api/demo/taskhall'
import { User, imageError } from './util'
import { getAppEnvConfig } from '@/utils/env';
const { VITE_GLOB_UPLOAD_URL } = getAppEnvConfig();
const props = defineProps(['getValueType'])
watch(() => props.getValueType, () => {
getValue()
})
onMounted(() => {
getValue()
})
const handoffButton = ref('week')
const firstPlace = ref<User | null>(null)
const secondPlace = ref<User | null>(null)
const thirdPlace = ref<User | null>(null)
const getValue = () => {
GetRankingList({flag: handoffButton.value}).then(res => {
console.log('最佳员工排行', res)
firstPlace.value = res[0]? res[0]: null
secondPlace.value = res[1]? res[1]: null
thirdPlace.value = res[2]? res[2]: null
})
}
const changeRankingType = (type: string) => {
handoffButton.value = type
getValue()
}
</script>
<style lang="scss" scoped>
.handoff-button{
width: 77px;
height: 31px;
background-image: url('/public/taskhall/best_employee_button.png');
display: flex;
align-items: center;
justify-content: center;
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 14px;
color: #FFFFFF;
cursor: pointer;
}
.handoff-button-active{
background-image: url('/public/taskhall/best_employee_button_select.png');
}
.best-employee{
height: 300px;
padding-top: 155px;
padding-left: 68px;
position: relative;
user-select: none;
.podium{
width: 342px;
height: 127px;
background-image: url('/public/taskhall/podium.png');
position: relative;
// display: flex;
// justify-content: center;
// align-items: center;
.first-place{
position: absolute;
top: calc(50% - 165px);
left: 50%;
transform: translate(-50%, -50%);
width: 148px;
height: 148px;
background-image: url('/public/taskhall/light.png');
display: flex;
justify-content: center;
align-items: center;
.user-image{
width: 67px;
height: 67px;
border-radius: 50%;
border: 2px solid #F3DF8E;
}
.first-mark{
width: 42px;
height: 37px;
background-image: url('/public/taskhall/first_mark.png');
position: absolute;
top: 20px;
left: 31px;
}
.user-name{
position: absolute;
top: calc(50% + 47px);
left: 50%;
transform: translateX(-50%);
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 14px;
color: #FFFFFF;
white-space: nowrap;
}
.gap{
position: absolute;
top: calc(50% + 66px);
left: 50%;
transform: translateX(-50%);
width: 45px;
height: 17px;
border-radius: 8px;
background: #DB420F;
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 14px;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
}
}
.second-place{
position: absolute;
top: calc(50% - 135px);
left: calc(50% - 112px);
transform: translate(-50%, -50%);
width: 148px;
height: 148px;
background-image: url('/public/taskhall/light.png');
display: flex;
justify-content: center;
align-items: center;
.user-image{
width: 67px;
height: 67px;
border-radius: 50%;
border: 2px solid #929292;
}
.second-mark{
width: 42px;
height: 37px;
background-image: url('/public/taskhall/second_mark.png');
position: absolute;
top: 21px;
left: 27px;
}
.user-name{
position: absolute;
top: calc(50% + 47px);
left: 50%;
transform: translateX(-50%);
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 14px;
color: #FFFFFF;
white-space: nowrap;
}
.gap{
position: absolute;
top: calc(50% + 66px);
left: 50%;
transform: translateX(-50%);
width: 45px;
height: 17px;
border-radius: 8px;
background: #0C76D0;
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 14px;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
}
}
.third-place{
position: absolute;
top: calc(50% - 118px);
left: calc(50% + 108px);
transform: translate(-50%, -50%);
width: 148px;
height: 148px;
background-image: url('/public/taskhall/light.png');
display: flex;
justify-content: center;
align-items: center;
.user-image{
width: 67px;
height: 67px;
border-radius: 50%;
border: 2px solid #815830;
}
.third-mark{
width: 43px;
height: 39px;
background-image: url('/public/taskhall/third_mark.png');
position: absolute;
top: 19px;
right: 27px;
}
.user-name{
position: absolute;
top: calc(50% + 47px);
left: 50%;
transform: translateX(-50%);
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 14px;
color: #FFFFFF;
white-space: nowrap;
}
.gap{
position: absolute;
top: calc(50% + 66px);
left: 50%;
transform: translateX(-50%);
width: 45px;
height: 17px;
border-radius: 8px;
background: #AA803C;
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 14px;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
</style>

View File

@ -0,0 +1,7 @@
export interface User {
HeadIcon: string;
Name: string;
count: number;
userid: string;
}
export const imageError = 'data:image/png;base64,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'

View File

@ -0,0 +1,105 @@
<template>
<div class="sub_title" style="margin-bottom: 0px">完成任务</div>
<div style="height: 150px;" id="complete-task-num"></div>
</template>
<script setup lang="ts">
import { onMounted, ref, onBeforeUnmount, defineProps, watch } from "vue"
import * as echarts from 'echarts';
import { GetCompleteTaskList } from '@/api/demo/taskhall'
const props = defineProps(['getValueType'])
watch(() => props.getValueType, () => {
getValue()
})
let myChart:any = {}
const dayList = ref([])
const valueList = ref([])
onMounted(() => {
let chartDom = document.getElementById('complete-task-num');
myChart = echarts.init(chartDom)
getValue()
})
const getValue = () => {
GetCompleteTaskList().then(res => {
console.log('已完成任务获取数据',res)
dayList.value = res.map(item => {
return item.time.slice(5,10).split('-').join('.')
})
valueList.value = res.map(item => {
return item.count
})
setChartsOptions()
})
}
onBeforeUnmount(() => {
myChart.dispose();
})
const setChartsOptions = () => {
myChart.setOption({
xAxis: {
type: 'category',
data: dayList.value,
axisTick:{
show: false
},
axisLine:{
lineStyle:{
color: '#0095FF',
}
},
axisLabel:{
interval: 1,
margin: 9,
color: '#FFFFFF',
fontFamily: 'DINPro',
fontSize: 12,
fontWeight: 500,
}
},
yAxis: {
type: 'value',
splitLine: {
lineStyle: {
color: ['#0095FF'],
opacity: 0.3,
},
width: 1,
},
axisLabel:{
color: '#8FADCC',
fontFamily: 'DINPro',
fontSize: 12,
}
},
series: [
{
data: valueList.value,
type: 'bar',
itemStyle:{
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#7FB5FF' },
{ offset: 1, color: '#006AFF' }
])
}
}
],
grid:{ //
top:"20px",
left:"30px",
right:"10px",
bottom:"20px"
}
})
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,200 @@
<template>
<div class="sub_title" style="margin-bottom: 14px;">组排名</div>
<div class="group-rankings">
<div :class="`group-rankings-item ${getClassName(index)}`" v-for="(item,index) in groupRankList" :key="index">
<div class="group-mark">
<span class="other-number" v-if="index > 2">{{ index+1 }}</span>
</div>
<div class="group-content">
<div class="title">{{`数据中心【${item.Name}`}}</div>
<div class="statistics">
<div class="statistics-left">
<div class="mark">
<div class="other-mark" v-if="index > 2"></div>
</div>
<div class="quantity">{{item.count}}</div>
</div>
<div class="statistics-right">
<div class="mark">
<div class="other-mark" v-if="index > 2"></div>
</div>
<div class="quantity" v-if="false"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, defineProps, watch } from "vue"
import { GetGroupRankingList } from '@/api/demo/taskhall'
const props = defineProps(['getValueType'])
watch(() => props.getValueType, () => {
getValue()
})
onMounted(() => {
getValue()
})
const getValue = () => {
GetGroupRankingList().then(res => {
console.log('组排名',res)
groupRankList.value = res
})
}
const groupRankList = ref<{Name:string;count:number}[]>([])
const getClassName = (index) => {
switch(index){
case 0: return 'first-group'
case 1: return 'second-group'
case 2: return 'third-group'
default: return 'other'
}
}
</script>
<style lang="scss" scoped>
.group-rankings{
width: 472px;
height: 223px;
margin-bottom: 10px;
overflow: auto;
scrollbar-width: none;
::-webkit-scrollbar {
width: 0;
height: 0;
}
.first-group{
.group-mark{
background-image: url('/public/taskhall/first_group_mark.png');
}
.statistics-left{
display: flex;
.mark{
background-image: url('/public/taskhall/first_group_mark_s.png');
}
}
.statistics-right{
display: flex;
.mark{
background-image: url('/public/taskhall/first_group_mark_m.png');
}
}
}
.second-group{
.group-mark{
background-image: url('/public/taskhall/second_group_mark.png');
}
.statistics-left{
display: flex;
.mark{
background-image: url('/public/taskhall/second_group_mark_s.png');
}
}
.statistics-right{
display: flex;
.mark{
background-image: url('/public/taskhall/second_group_mark_m.png');
}
}
}
.third-group{
.group-mark{
background-image: url('/public/taskhall/third_group_mark.png');
}
.statistics-left{
display: flex;
.mark{
background-image: url('/public/taskhall/third_group_mark_s.png');
}
}
.statistics-right{
display: flex;
.mark{
background-image: url('/public/taskhall/third_group_mark_m.png');
}
}
}
.group-rankings-item{
width: 472px;
height: 70px;
background-image: url('/public/taskhall/group_rankings_item_background.png');
background-size: contain;
background-repeat: no-repeat;
padding-left: 6px;
display: flex;
margin-bottom: 4px;
.group-mark{
width: 70px;
height: 70px;
display: flex;
align-items: center;
justify-content: center;
.other-number{
font-family: DINPro;
font-weight: 500;
font-size: 29px;
color: #FFFFFF;
user-select: none;
}
}
.group-content{
padding-top: 13px;
padding-left: 12px;
flex: 1;
.title{
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 16px;
color: #FFFFFF;
margin-bottom: 8px;
line-height: 15px;
}
.statistics{
height: 26px;
display: flex;
align-items: center;
.mark{
width: 22px;
height: 26px;
// background-image: url('/public/taskhall/first_group_mark_m.png');
margin-right: 10px;
user-select: none;
display: flex;
align-items: center;
justify-content: center;
.other-mark{
width: 8px;
height: 8px;
background: #036CFF;
border-radius: 50%;
}
}
.quantity{
font-family: DINPro;
font-weight: 500;
font-size: 20px;
color: #FFFFFF;
width: 136px;
user-select: none;
}
.statistics-left{
display: flex
}
.statistics-right{
display: flex
}
}
}
}
.group-rankings-item:last-child{
margin-bottom: 0px;
}
}
</style>

View File

@ -0,0 +1,145 @@
<template>
<div class="header">
<div class="span-div">
<div class="title">任务大厅</div>
<div class="sub-title">TASK&nbsp;&nbsp;HALL</div>
</div>
<div class="weather-time">
<div class="weather">{{weather? weather: ''}}</div>
<div class="temperature">{{temperature? `${temperature}°`: ''}}</div>
<div class="air-mark good-air"></div>
<div class="air">良好</div>
<div class="week">{{week}}</div>
<div class="inteval"></div>
<div class="date">{{date}}</div>
<div class="time">{{time}}</div>
</div>
</div>
</template>
<script setup lang="ts">
import axios from "axios";
import { onMounted,ref, onBeforeUnmount } from "vue"
import dayjs from 'dayjs';
const weather = ref()
const temperature = ref()
const date = ref(dayjs().format('YYYY-MM-DD'))
const time = ref(dayjs().format('HH:mm'))
const inteval = ref()
const week = ref()
let weekList = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
onMounted(() => {
let day = dayjs().day();
week.value = weekList[day]
axios({
method: 'get',
url: `https://cn.apihz.cn/api/tianqi/tqyb.php?id=88888888&key=88888888&sheng=山东&place=临沂`,
}).then(res => {
console.log('获取天气',res)
weather.value = res.data.weather1
temperature.value = res.data.temperature
})
inteval.value = setInterval(() => {
date.value = dayjs().format('YYYY-MM-DD')
time.value = dayjs().format('HH:mm')
}, 1000);
})
onBeforeUnmount(() => {
clearInterval(inteval.value)
})
</script>
<style lang="scss" scoped>
.header{
width: 100%;
height: 122px;
background-image: url('/public/taskhall/header.png');
display: flex;
justify-content: center;
position: relative;
user-select: none;
.span-div{
width: 208px;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 33px;
.title{
font-family: HuXiaoBo-NanShen;
font-weight: 400;
font-size: 46px;
color: #FFFFFF;
letter-spacing: 6px;
}
.sub-title{
font-family: Roboto;
font-weight: 100;
font-size: 14px;
color: #6B95B3;
}
}
.weather-time{
position: absolute;
display: flex;
top: 36px;
right: 43px;
font-size: 16px;
color: #9EB2D5;
align-items: center;
.weather{
font-family: Microsoft YaHei;
font-weight: 400;
opacity: 0.8;
margin-right: 9px;
}
.temperature{
font-family: DINPro;
font-weight: bold;
font-size: 16px;
opacity: 0.8;
margin-right: 13px;
}
.air-mark{
width: 4px;
height: 4px;
border-radius: 2px;
margin-right: 6px;
}
.good-air{
background: #1ACDA6;
}
.air{
font-family: Microsoft YaHei;
font-weight: 400;
opacity: 0.8;
margin-right: 20px;
}
.week{
font-family: Microsoft YaHei;
font-weight: 400;
opacity: 0.8;
margin-right: 18px;
}
.inteval{
width: 1px;
height: 14px;
background: #F59969;
border: 1px solid #657799;
margin-right: 17px;
}
.date{
font-family: DIN;
font-weight: bold;
opacity: 0.8;
margin-right: 10px;
}
.time{
font-family: DIN;
font-weight: bold;
opacity: 0.8;
}
}
}
</style>

View File

@ -0,0 +1,489 @@
<template>
<div class="sub_title">任务区</div>
<div class="task-area-div" id="task-area-div">
<template v-for="(item,index) in taskList" :key="index">
<div class="task-big-item interval" v-if="index < 3">
<div class="left-item">
<div class="item-title">数据中心</div>
<div class="item-sub-title">{{ item.TaskName }}</div>
<div class="progress">
<a-progress
style="margin: 0;"
:percent="item.CompleteCount / item.ShpCount * 100"
:show-info="false"
:size="10"/>
<div class="progress-mark"></div>
<span class="progress-span">{{ `${item.CompleteCount} / ${item.ShpCount}` }}</span>
</div>
<div class="item-button" @click="showSelectModal(item)">
<span class="button-span">未领取</span>
<span class="button-span-shadow">未领取</span>
</div>
</div>
<div class="right-item">
<div class="item-mark"></div>
</div>
</div>
<div class="task-small-item interval" v-else>
<div class="mark-out-div">
<div class="item-mark"></div>
<div class="span-div">
<div class="title">{{ item.TaskName }}</div>
<div class="progress">
<a-progress
style="margin: 0;"
:percent="item.CompleteCount / item.ShpCount * 100"
:show-info="false"
:size="10"/>
<div class="progress-mark"></div>
<span class="progress-span">{{ `${item.CompleteCount} / ${item.ShpCount}` }}</span>
</div>
</div>
</div>
<div class="button-div">
<div class="button-item" @click="showSelectModal(item)">
<span class="button-span">领取</span>
<span class="button-span-shadow">领取</span>
</div>
</div>
</div>
</template>
</div>
<a-modal
v-model:open="openSelectTaskModal"
style="top: 311px"
:footer="null"
:getContainer="getContainer"
:maskClosable="false"
>
<div class="close-button" @click="closeModal"></div>
<div class="modal-title">数据中心任务3-平邑图斑</div>
<div class="modal-content">
<div
:class="`select-item ${submitSelectListId.includes(item.id)? 'select-item-check': ''}`"
v-for="(item,index) in selectModalList"
:key="index"
@click="selectItem(item.id)">
{{ `${item.beginNum}~${item.endNum}` }}
</div>
</div>
<div style="display: flex; justify-content: flex-end;height: 43px;padding-right: 27px;">
<div class="submit-button" @click="submitTask">
<span class="button-span">提交</span>
<span class="button-span button-span-shadow">提交</span>
</div>
</div>
</a-modal>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue"
import { GetTaskList, GetgrouptaskList, ReciveTask } from '@/api/demo/taskhall'
import { Item, SelectModalItem } from './util'
import { message } from "ant-design-vue"
import { signal } from '@/utils/signalR';
const signalConnection = ref()
onMounted(() => {
getValue()
signal.start().then(() => {
console.log('SignalR Connected');
signal.on("RevMsg", (user, message, time, id, issystem) => {
console.log('报警', user, message, time, id, issystem);
let messageData = JSON.parse(message);
if (user == 'InsTask') {
console.log('获取数据',user, messageData, time, id, issystem)
getValue()
}
});
})
signalConnection.value = signal
})
onBeforeUnmount(() => {
if(signalConnection.value){
signalConnection.value.stop().then(() => console.log('SignalR Disconnected'))
.catch(err => console.error('Error stopping connection:', err));
}
})
const getValue = () => {
GetTaskList().then(res => {
console.log('任务区列表',res)
taskList.value = res
})
}
const taskList: any = ref<Item[]>([])
const openSelectTaskModal = ref(false)
const selectModalList = ref<SelectModalItem[]>([])
const submitSelectListId = ref<string[]>([])
const getContainer = () => {
return document.getElementById('task-area-div')
}
const showSelectModal = (item) => {
GetgrouptaskList({id: item.Id}).then(res => {
console.log('可选弹窗数据列表',res)
selectModalList.value = res
openSelectTaskModal.value = true
})
}
const selectItem = (id) => {
if(submitSelectListId.value.includes(id)){
submitSelectListId.value = submitSelectListId.value.filter(item => item !== id)
}else{
submitSelectListId.value.push(id)
}
}
const submitTask = () => {
if(submitSelectListId.value.length < 1){
message.warning('请选择后提交')
return
}
ReciveTask(submitSelectListId.value).then(res => {
console.log('提交选择',res)
if(res){
message.success('领取成功')
closeModal()
}
})
}
const closeModal = () => {
openSelectTaskModal.value = false
submitSelectListId.value = []
}
</script>
<style lang="scss" scoped>
.select-task-modal{
background-color: #036DFF;
}
.task-area-div{
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
height: 580px;
align-content: flex-start;
overflow: auto;
scrollbar-width: none;
::-webkit-scrollbar {
width: 0;
height: 0;
}
:deep(.ant-modal-content){
padding: 0px;
width: 481px;
height: 355px;
background-image: url('/public/taskhall/task_area_select_modal.png');
background-repeat: no-repeat;
background-color: transparent;
}
:deep(.ant-modal-close){
display: none;
}
}
.task-big-item{
width: 418px;
height: 239px;
background-image: url('/public/taskhall/item_big_background.png');
background-size: contain;
background-repeat: no-repeat;
margin-bottom: 14px;
padding-top: 26px;
padding-left: 27px;
display: flex;
.left-item{
width: 228px;
margin-right: 36px;
.item-title{
font-family: AlibabaPuHuiTiR;
font-weight: 400;
font-size: 30px;
color: #FFFFFF;
margin-bottom: 12PX;
}
.item-sub-title{
font-family: AlibabaPuHuiTiR;
font-weight: 400;
font-size: 22px;
color: #FFFFFF;
margin-bottom: 25px;
}
.progress{
width: 228px;
height: 10px;
display: flex;
align-items: center;
position: relative;
margin-bottom: 33px;
:deep(.ant-progress-bg){
background-image: linear-gradient(0deg, #00FF95 0%, #7FFFCA 100%) !important;
}
.progress-span{
position: absolute;
top: 45%;
left: 50%;
transform: translate(-50%,-50%);
font-family: DINPro;
font-weight: 500;
font-size: 18px;
color: #FFFFFF;
user-select: none;
}
}
.item-button{
width: 145px;
height: 53px;
background-image: url('/public/taskhall/big_item_button.png');
box-shadow: 0px 5px 13px 0px rgba(7,112,255,0.38);
border-radius: 26px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
cursor: pointer;
.button-span{
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 24px;
color: #FAFDFF;
background: linear-gradient(#E5E5E5, #4fadff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
position: relative;
z-index: 2;
user-select: none;
}
.button-span-shadow{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 24px;
color: rgb(250, 253, 255, 0);
text-shadow: 0px 2px 4px rgba(0,40,45,1);
z-index: 1;
user-select: none;
}
}
}
.right-item{
padding-top: 23px;
.item-mark{
width: 69px;
height: 78px;
background-image: url('/public/taskhall/big_item_mark.png');
}
}
}
.task-small-item{
width: 418px;
height: 99px;
background-image: url('/public/taskhall/item_small_background.png');
background-size: contain;
background-repeat: no-repeat;
margin-bottom: 10px;
padding-top: 11px;
padding-left: 16px;
display: flex;
.mark-out-div{
width: 270px;
display: flex;
.item-mark{
width: 69px;
height: 78px;
background-image: url('/public/taskhall/small_item_mark.png');
margin-right: 12px;
}
.span-div{
padding-top: 12px;
.title{
font-family: AlibabaPuHuiTiR;
font-weight: 400;
font-size: 20px;
color: #FFFFFF;
margin-bottom: 16px;
}
.progress{
width: 124px;
height: 10px;
// border-radius: 5px;
// background: linear-gradient(268deg, #036DFF 0%, #7AD3FF 100%);
position: relative;
display: flex;
align-items: center;
// justify-content: center;
// line-height: 13px;
// font-family: DINPro;
// font-weight: 500;
// font-size: 18px;
// color: #FFFFFF;
:deep(.ant-progress-bg){
background-image: linear-gradient(268deg, #036DFF 0%, #7AD3FF 100%) !important;
}
.progress-span{
position: absolute;
top: 50%;
left: 55%;
transform: translate(-50%, -50%);
font-family: DINPro;
font-weight: 500;
font-size: 15px;
color: #FFFFFF;
white-space: nowrap;
user-select: none;
}
}
}
}
.button-div{
padding-top: 15px;
.button-item{
width: 109px;
height: 49px;
background-image: url('/public/taskhall/small_item_button.png');
box-shadow: 0px 5px 13px 0px rgba(7,112,255,0.38);
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
cursor: pointer;
.button-span{
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 24px;
color: #FAFDFF;
// text-shadow: 0px 2px 4px rgba(0,40,45,0.7);
background: linear-gradient( #E5E5E5, rgba(79,173,255,1));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
position: relative;
z-index: 2;
user-select: none
}
.button-span-shadow{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 24px;
color: rgb(250, 253, 255, 0);
text-shadow: 0px 2px 4px rgba(0,40,45,1);
z-index: 1;
user-select: none;
}
}
}
}
.interval:nth-child(3n-1){
margin-right: 20px;
}
.interval:nth-child(3n-2){
margin-right: 20px;
}
.progress-mark{
position: absolute;
width: 22px;
height: 26px;
background-image: url('/public/taskhall/progress_mark.png');
top: -9px;
left: -2px;
}
.close-button{
position: absolute;
top: 3px;
right: 2px;
width: 49px;
height: 46px;
background-image: url('/public/taskhall/modal_close.png');
cursor: pointer;
}
.modal-title{
height: 72px;
margin-left: 7px;
margin-right: 7px;
padding-top: 30px;
padding-left: 21px;
border-bottom: 1px solid #052A6B;
font-family: AlibabaPuHuiTiR;
font-weight: 400;
font-size: 24px;
color: #42D9FF;
line-height: 23px;
}
.modal-content{
padding-top: 13px;
padding-left: 29px;
padding-right: 18px;
height: 183px;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
overflow: auto;
margin-bottom: 20px;
.select-item{
width: 208px;
height: 52px;
background-image: url('/public/taskhall/select_item.png');
background-size: contain;
background-repeat: no-repeat;
margin-right: 9px;
margin-bottom: 7px;
padding-left: 64px;
padding-top: 19px;
font-family: DINPro;
font-weight: 500;
font-size: 22px;
color: #FFFFFF;
line-height: 17px;
cursor: pointer;
user-select: none;
}
.select-item-check{
background-image: url('/public/taskhall/select_item_check.png');
}
}
.submit-button{
width: 120px;
height: 43px;
background-image: url('/public/taskhall/modal_submit_button.png');
display: flex;
align-items: center;
justify-content: center;
position: relative;
cursor: pointer;
.button-span{
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 24px;
color: #FAFDFF;
background: linear-gradient(#E5E5E5, #4fadff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
position: relative;
z-index: 2;
user-select: none;
}
.button-span-shadow{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 24px;
color: rgb(250, 253, 255, 0);
text-shadow: 0px 2px 4px rgba(0,40,45,1);
z-index: 1;
user-select: none;
}
}
</style>

View File

@ -0,0 +1,14 @@
export interface Item {
Id: string;
TaskName: string;
CompleteCount: number;
ShpCount: number;
State: number;
}
export interface SelectModalItem {
id: string;
taskId: string;
beginNum: number;
endNum: number;
groupName: string;
}

View File

@ -0,0 +1,89 @@
<template>
<div class="sub_title" style="margin-bottom: 14px;">在办任务</div>
<div class="working-task-div">
<div class="working-task-item" v-for="(item,index) in workingTask" :key="index">
<div class="mark"></div>
<img class="user-image" :src="`${item.HeadIcon? `${VITE_GLOB_UPLOAD_URL}/${item.HeadIcon}`: imageError}`"/>
<div class="user-name">{{item.Name}}</div>
<div class="user-working-number">{{item.count}}</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, defineProps, watch } from "vue"
import { GetTaskingList } from '@/api/demo/taskhall'
import { getAppEnvConfig } from '@/utils/env';
import { imageError } from '@/views/demo/taskhall/BestEmployee/util'
const { VITE_GLOB_UPLOAD_URL } = getAppEnvConfig();
const props = defineProps(['getValueType'])
watch(() => props.getValueType, () => {
getValue()
})
onMounted(() => {
getValue()
})
const getValue = () => {
GetTaskingList().then(res => {
console.log('再办任务数据',res)
workingTask.value = res
})
}
const workingTask = ref<{HeadIcon:string;Name:string;count:number}[]>([])
</script>
<style lang="scss" scoped>
.working-task-div{
height: 181px;
overflow: auto;
scrollbar-width: none;
::-webkit-scrollbar {
width: 0;
height: 0;
}
.working-task-item{
position: relative;
display: flex;
align-items: center;
width: 472px;
height: 38px;
background-image: url('/public/taskhall/working_task_background.png');
background-size: contain;
background-repeat: no-repeat;
padding-left: 17px;
margin-bottom: 7px;
user-select: none;
.mark{
width: 5px;
height: 5px;
background-image: url('/public/taskhall/working_task_mark.png');
position: absolute;
top: 0px;
left: 0px;
}
.user-image{
width: 34px;
height: 34px;
border-radius: 50%;
border: 1px solid #036CFF;
margin-right: 14px;
}
.user-name{
font-family: AlibabaPuHuiTiM;
font-weight: 500;
font-size: 16px;
color: #FFFFFF;
width: 242px;
}
.user-working-number{
font-family: DINPro;
font-weight: 500;
font-size: 20px;
color: #FFFFFF;
}
}
}
</style>

View File

@ -0,0 +1,103 @@
<template>
<div class="background">
<!-- 头部 -->
<Header />
<div class="content">
<div class="left-content">
<!-- 任务区 -->
<TaskArea />
<!-- 完成任务 -->
<CompleteTask :getValueType="getValueType"/>
</div>
<div class="right-content">
<!-- 最佳员工 -->
<BestEmployee :getValueType="getValueType"/>
<!-- 组排名 -->
<GroupRanings :getValueType="getValueType"/>
<!-- 再办任务 -->
<WorkingTask :getValueType="getValueType"/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Header from './Header/index.vue'
import TaskArea from './TaskArea/index.vue'
import CompleteTask from './CompleteTask/index.vue'
import BestEmployee from './BestEmployee/index.vue'
import GroupRanings from './GroupRankings/index.vue'
import WorkingTask from './WorkingTask/index.vue'
import { onMounted, ref, onBeforeUnmount } from 'vue'
import { v4 as uuidv4 } from 'uuid';
const inteval = ref()
const getValueType = ref()
onMounted(() => {
inteval.value = setInterval(() => {
getValueType.value = uuidv4()
console.log('getValueType.value',getValueType.value)
}, 60000)
})
onBeforeUnmount(() => {
clearInterval(inteval.value)
})
</script>
<style lang="scss" scoped>
.background{
width: 100%;
height: 100vh;
background-image: url('/public/taskhall/background.png');
:deep(.sub_title){
width: 405px;
height: 27px;
background-image: url('/public/taskhall/sub_title_background.png');
background-repeat: no-repeat;
font-family: HuXiaoBo-NanShen;
font-weight: 400;
font-size: 20px;
color: #FFFFFF;
margin-bottom: 17px;
padding-top: 3px;
padding-left: 17px;
user-select: none;
cursor: default;
}
}
.content{
padding-left: 53px;
padding-right: 42px;
display: flex;
height: calc(100% - 122px);
padding-bottom: 34px;
.left-content{
width: 1294px;
margin-right: 50px;
}
.right-content{
width: 472px;
}
.sub_title{
width: 405px;
height: 27px;
background-image: url('/public/taskhall/sub_title_background.png');
background-repeat: no-repeat;
font-family: HuXiaoBo-NanShen;
font-weight: 400;
font-size: 20px;
color: #FFFFFF;
margin-bottom: 17px;
padding-top: 3px;
padding-left: 17px;
user-select: none;
cursor: default;
}
}
</style>