|
|
<template>
|
|
|
<div class="body">
|
|
|
<div class="dashboard-container">
|
|
|
<div class="row row1">
|
|
|
<div class="weather">
|
|
|
<div class="left">
|
|
|
<h3>工作台</h3>
|
|
|
<div class="d-flex">
|
|
|
<div>欢迎回来,{{ name }}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="center">
|
|
|
<el-button
|
|
|
style="padding: 6px 15px"
|
|
|
type="primary"
|
|
|
size="small"
|
|
|
round
|
|
|
@click="$router.push('/attendance')"
|
|
|
>去打卡</el-button
|
|
|
>
|
|
|
</div>
|
|
|
|
|
|
<div class="right">
|
|
|
<div class="weather__icon">
|
|
|
<i :class="weatherIcon.get(weather.weather)"></i>
|
|
|
</div>
|
|
|
<div class="weather__weather">
|
|
|
<div>{{ $moment().format("dddd") }}</div>
|
|
|
<div>{{ weather.weather }}</div>
|
|
|
</div>
|
|
|
<div class="weather__temperature">
|
|
|
<div class="celsius">
|
|
|
<span>
|
|
|
{{ weather.temperature }}
|
|
|
</span>
|
|
|
<span>°C</span>
|
|
|
</div>
|
|
|
<div class="wind">
|
|
|
<span>{{ weather.winddirection }}</span>
|
|
|
<span> {{ weather.windpower }}级</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="mycard calendar">
|
|
|
<div class="mycard__title calendar__title d-flex">
|
|
|
<div>工作日历</div>
|
|
|
|
|
|
<el-date-picker
|
|
|
v-model="calendar"
|
|
|
type="month"
|
|
|
size="small"
|
|
|
style="
|
|
|
width: 160px;
|
|
|
border-radius: 10px;
|
|
|
background-color: #ffffff;
|
|
|
border: 1px solid #d1d1d1;
|
|
|
"
|
|
|
></el-date-picker>
|
|
|
</div>
|
|
|
<div class="mycard__body calendar__body">
|
|
|
<el-calendar v-model="calendar">
|
|
|
<template #dateCell="{ date, data }">
|
|
|
<div
|
|
|
class="sign-status"
|
|
|
:class="
|
|
|
(getTodayAttendance(data.day) && (getTodayAttendance(data.day).sign_in_at || getTodayAttendance(data.day).sign_out_at)) ? 'has-attendance' : ''
|
|
|
"
|
|
|
>
|
|
|
{{ data.day.split("-")[2] }}
|
|
|
|
|
|
<template v-if="getTodayAttendance(data.day)">
|
|
|
<div
|
|
|
class="work-overtime"
|
|
|
v-if="
|
|
|
getTodayAttendance(data.day) && getTodayAttendance(data.day).jiaban instanceof Array && getTodayAttendance(data.day).jiaban.filter(i => i).length > 0
|
|
|
"
|
|
|
>
|
|
|
加班
|
|
|
</div>
|
|
|
<div
|
|
|
class="sign-duty"
|
|
|
v-if="
|
|
|
getTodayAttendance(data.day, 'on_duty_schedules')
|
|
|
"
|
|
|
>
|
|
|
{{
|
|
|
getTodayAttendance(data.day, 'on_duty_schedules').status ? '已值班' : '待值班'
|
|
|
}}
|
|
|
</div>
|
|
|
<div
|
|
|
class="sign-in"
|
|
|
v-if="
|
|
|
getTodayAttendance(data.day) &&
|
|
|
getTodayAttendance(data.day).sign_in_at
|
|
|
"
|
|
|
>
|
|
|
{{
|
|
|
$moment(getTodayAttendance(data.day).sign_in_at).format(
|
|
|
"HH:mm"
|
|
|
)
|
|
|
}}
|
|
|
</div>
|
|
|
<div
|
|
|
class="sign-out"
|
|
|
v-if="
|
|
|
getTodayAttendance(data.day) &&
|
|
|
getTodayAttendance(data.day).sign_out_at
|
|
|
"
|
|
|
>
|
|
|
{{
|
|
|
$moment(
|
|
|
getTodayAttendance(data.day).sign_out_at
|
|
|
).format("HH:mm")
|
|
|
}}
|
|
|
</div>
|
|
|
<div
|
|
|
class="sign-away"
|
|
|
v-if="getTodayAttendance(data.day) && getTodayAttendance(data.day).chuchai && getTodayAttendance(data.day).chuchai instanceof Array && (getTodayAttendance(data.day).chuchai[0] || getTodayAttendance(data.day).chuchai[1])"
|
|
|
>
|
|
|
出差
|
|
|
</div>
|
|
|
<div
|
|
|
class="sign-leave"
|
|
|
v-if="getTodayAttendance(data.day) && getTodayAttendance(data.day).qingxiujia && getTodayAttendance(data.day).qingxiujia instanceof Array && getTodayAttendance(data.day).qingxiujia[0]"
|
|
|
>
|
|
|
上午请假
|
|
|
</div>
|
|
|
<div
|
|
|
class="sign-leave"
|
|
|
v-if="getTodayAttendance(data.day) && getTodayAttendance(data.day).qingxiujia && getTodayAttendance(data.day).qingxiujia instanceof Array && getTodayAttendance(data.day).qingxiujia[1]"
|
|
|
>
|
|
|
下午请假
|
|
|
</div>
|
|
|
</template>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-calendar>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="row row2">
|
|
|
<div class="mycard quick-menu">
|
|
|
<div class="mycard__title">
|
|
|
<span>快捷导航</span>
|
|
|
</div>
|
|
|
|
|
|
<div class="mycard__body quick-menu__body">
|
|
|
<el-badge :value="item.num"
|
|
|
:max="99"
|
|
|
:hidden="!item.num"
|
|
|
class="item"
|
|
|
v-for="item in quickMenus"
|
|
|
:key="item.key">
|
|
|
<router-link
|
|
|
:to="item.url"
|
|
|
tag="div"
|
|
|
>
|
|
|
<div>
|
|
|
{{ item.name }}
|
|
|
</div>
|
|
|
</router-link>
|
|
|
</el-badge>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="mycard flow">
|
|
|
<div class="mycard__title">
|
|
|
<span>常用流程</span>
|
|
|
</div>
|
|
|
|
|
|
<div class="mycard__body flow__body">
|
|
|
<div
|
|
|
v-for="item in usualFlows"
|
|
|
:key="item.key"
|
|
|
@click="toCreate(item)">
|
|
|
<div class="flow-cover">
|
|
|
<template v-if="item.icon">
|
|
|
<Icon class="flow__body--icon" :icon="item.icon"></Icon>
|
|
|
</template>
|
|
|
<template v-else>
|
|
|
<i class="el-icon-edit flow__body--icon"></i>
|
|
|
</template>
|
|
|
</div>
|
|
|
<span class="flow__body--name">{{ item.name }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="todo mycard">
|
|
|
<div class="mycard__title">
|
|
|
<span>待办事项</span>
|
|
|
</div>
|
|
|
|
|
|
<div class="mycard__body">
|
|
|
<el-table
|
|
|
v-loading="noticeLoading"
|
|
|
style="width: 100%"
|
|
|
size="mini"
|
|
|
:header-cell-style="{
|
|
|
'font-weight': '600',
|
|
|
background: '#eaf2ff',
|
|
|
color: '#515a6e',
|
|
|
}"
|
|
|
element-loading-text="拼命加载中"
|
|
|
element-loading-spinner="el-icon-loading"
|
|
|
element-loading-background="rgba(255, 255, 255, 0.8)"
|
|
|
:data="notice"
|
|
|
>
|
|
|
<el-table-column
|
|
|
type="index"
|
|
|
width="46"
|
|
|
label="序号"
|
|
|
align="center"
|
|
|
/>
|
|
|
<el-table-column
|
|
|
v-for="(item, index) in noticeTable"
|
|
|
:key="index"
|
|
|
:width="item.width"
|
|
|
:label="item.title"
|
|
|
:prop="item.key"
|
|
|
:show-overflow-tooltip="item['show-overflow-tooltip']"
|
|
|
header-align="center"
|
|
|
:align="item.align"
|
|
|
:formatter="item.formatter"
|
|
|
/>
|
|
|
<el-table-column
|
|
|
label="操作"
|
|
|
header-align="center"
|
|
|
width="150"
|
|
|
fixed="right"
|
|
|
>
|
|
|
<template #default="{ row }">
|
|
|
<el-button
|
|
|
size="mini"
|
|
|
style="padding: 5px 10px"
|
|
|
@click="read(row)"
|
|
|
>设为已读</el-button
|
|
|
>
|
|
|
<el-button
|
|
|
size="mini"
|
|
|
type="primary"
|
|
|
style="padding: 5px 10px"
|
|
|
@click="handle(row)"
|
|
|
>办理</el-button
|
|
|
>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
<el-pagination
|
|
|
style="display: flex;justify-content: center;"
|
|
|
layout="prev, pager, next"
|
|
|
:total="noticeTotal"
|
|
|
:page-size.sync="noticeSelect.page_size"
|
|
|
@current-change="e => {
|
|
|
noticeSelect.page = e;
|
|
|
getNotices();
|
|
|
}"
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 办理-->
|
|
|
<vxe-modal
|
|
|
v-model="isShowModal"
|
|
|
:z-index="zIndex"
|
|
|
transfer
|
|
|
show-zoom
|
|
|
resize
|
|
|
:fullscreen="$store.getters.device === 'mobile'"
|
|
|
title="办理"
|
|
|
:width="defaultModalSize.width"
|
|
|
:height="defaultModalSize.height"
|
|
|
esc-closable
|
|
|
:padding="false"
|
|
|
>
|
|
|
<iframe
|
|
|
:src="modalUrl"
|
|
|
style="display: block;width: 100%;height: 100%;border: 0;"
|
|
|
frameborder="0"
|
|
|
/>
|
|
|
</vxe-modal>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import Icon from '@/layout/components/Sidebar/Icon.vue'
|
|
|
import { PopupManager } from "element-ui/lib/utils/popup";
|
|
|
import { mapGetters } from "vuex";
|
|
|
import axios from "axios";
|
|
|
import { getToken } from "@/utils/auth";
|
|
|
import { flow } from "@/api/flow";
|
|
|
import { index as configIndex } from "@/api/config";
|
|
|
import { index } from "@/api/attendance";
|
|
|
import {isExternal} from "@/utils/validate";
|
|
|
import { defaultModalSize } from "@/settings";
|
|
|
export default {
|
|
|
name: "Dashboard",
|
|
|
components: {
|
|
|
Icon
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
defaultModalSize,
|
|
|
modalUrl: "",
|
|
|
zIndex: PopupManager.nextZIndex(),
|
|
|
isShowModal: false,
|
|
|
|
|
|
weatherIcon: new Map([
|
|
|
["晴", "el-icon-sunny"],
|
|
|
["阴", "el-icon-cloudy"],
|
|
|
["多云", "el-icon-cloudy-and-sunny"],
|
|
|
["大雨", "el-icon-heavy-rain"],
|
|
|
["雷阵雨", "el-icon-lightning"],
|
|
|
["小雨", "el-icon-light-rain"],
|
|
|
["中雨", "el-icon-light-rain"],
|
|
|
]),
|
|
|
weather: {},
|
|
|
|
|
|
calendar: new Date(),
|
|
|
attendanceData: {
|
|
|
attendances: [],
|
|
|
},
|
|
|
|
|
|
quickMenus: [
|
|
|
{
|
|
|
name: "我收藏的",
|
|
|
url: "/flow/list/fav",
|
|
|
num: 0
|
|
|
},
|
|
|
{
|
|
|
name: "我办理过的",
|
|
|
url: "/flow/list/handled",
|
|
|
num: 0
|
|
|
},
|
|
|
{
|
|
|
name: "我发起的",
|
|
|
url: "/flow/list/my",
|
|
|
num: 0
|
|
|
},
|
|
|
{
|
|
|
name: "所有待办",
|
|
|
url: "/flow/list/todo",
|
|
|
num: 0
|
|
|
},
|
|
|
{
|
|
|
name: "抄送给我的",
|
|
|
url: "/flow/list/cc",
|
|
|
num: 0
|
|
|
},
|
|
|
],
|
|
|
|
|
|
flows: [],
|
|
|
usualFlows: [],
|
|
|
|
|
|
noticeTimer: null,
|
|
|
noticeLoading: false,
|
|
|
notice: [],
|
|
|
noticeSelect: {
|
|
|
page: 1,
|
|
|
page_size: 20,
|
|
|
from: window.MODULE_NAME || process.env.VUE_APP_MODULE_NAME,
|
|
|
},
|
|
|
noticeTotal: 0,
|
|
|
noticeTable: [
|
|
|
{
|
|
|
title: "下发时间",
|
|
|
key: "created_at",
|
|
|
width: 156,
|
|
|
align: "center",
|
|
|
formatter: (row, column, cellValue) => {
|
|
|
return this.$moment(cellValue).format("YYYY-MM-DD HH:mm:ss");
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
title: "内容",
|
|
|
key: "data.title",
|
|
|
align: "left",
|
|
|
"show-overflow-tooltip": true,
|
|
|
minWidth: 240,
|
|
|
},
|
|
|
],
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
...mapGetters(["name"]),
|
|
|
},
|
|
|
watch: {
|
|
|
isShowModal(newVal) {
|
|
|
if(newVal) {
|
|
|
this.zIndex = PopupManager.nextZIndex()
|
|
|
} else {
|
|
|
this.modalUrl = ''
|
|
|
}
|
|
|
},
|
|
|
calendar(newVal, oldVal) {
|
|
|
if (this.$moment(oldVal).format('YYYY-MM') !== this.$moment(newVal).format('YYYY-MM')) {
|
|
|
this.getAttendance()
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
toCreate(flow, cate) {
|
|
|
if(isExternal(flow.url)) {
|
|
|
const url = new URL(flow.url)
|
|
|
window.open(flow.url,'_blank')
|
|
|
} else if (flow.url) {
|
|
|
if (/\?.+/g.test(flow.url)) {
|
|
|
window.open(window.location.origin + flow.url,'_blank')
|
|
|
}
|
|
|
} else {
|
|
|
this.$router.push({
|
|
|
path: '/flow/create',
|
|
|
query: {
|
|
|
module_id: flow.id
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
},
|
|
|
getTodayAttendance(date,key = 'attendance') {
|
|
|
let temp = this.attendanceData.attendances.find((i) => i.date === date) ?? {}
|
|
|
return temp[key]
|
|
|
},
|
|
|
async getAttendance() {
|
|
|
try {
|
|
|
const res = await index({
|
|
|
month: this.$moment(this.calendar).format('YYYY-MM'),
|
|
|
});
|
|
|
this.attendanceData = res;
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
},
|
|
|
async getUsualFlows() {
|
|
|
try {
|
|
|
await this.getFlows();
|
|
|
const res = await configIndex({
|
|
|
filter: [
|
|
|
{
|
|
|
key: "key",
|
|
|
op: "eq",
|
|
|
value: "dashboard_menus",
|
|
|
},
|
|
|
],
|
|
|
});
|
|
|
this.usualFlows = this.flows.filter(
|
|
|
(i) => res.data[0]?.value?.indexOf(i.id.toString()) !== -1
|
|
|
);
|
|
|
console.log(this.usualFlows);
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
},
|
|
|
async getFlows() {
|
|
|
try {
|
|
|
const res = await flow();
|
|
|
this.flows = res.cates?.map((i) => i.customer_models).flat();
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
},
|
|
|
async getTotal() {
|
|
|
try {
|
|
|
const res = await axios.get(`${process.env.VUE_APP_BASE_API}/api/oa/statistics/notifications`,{
|
|
|
headers: {
|
|
|
Authorization: `Bearer ${getToken()}`,
|
|
|
}
|
|
|
});
|
|
|
if (res.status === 200) {
|
|
|
console.log(res)
|
|
|
this.quickMenus[3].num = res.data.data?.count_todo ?? 0
|
|
|
this.quickMenus[4].num = res.data.data?.count_unread_ccs ?? 0
|
|
|
}
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
},
|
|
|
async getWeather() {
|
|
|
try {
|
|
|
const res = await axios.get(
|
|
|
`https://restapi.amap.com/v3/weather/weatherInfo?city=320400&key=15ecd1e7de61e684959f43d8965a89f0`
|
|
|
);
|
|
|
if (res.status === 200) {
|
|
|
this.weather = res.data.lives[0];
|
|
|
}
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
},
|
|
|
|
|
|
async getNotices(loading = false) {
|
|
|
try {
|
|
|
if (loading) {
|
|
|
this.noticeLoading = true;
|
|
|
}
|
|
|
const res = await axios.get(
|
|
|
`${process.env.VUE_APP_BASE_API}/api/notification/todo`,
|
|
|
{
|
|
|
headers: {
|
|
|
Authorization: `Bearer ${getToken()}`,
|
|
|
},
|
|
|
params: this.noticeSelect,
|
|
|
}
|
|
|
);
|
|
|
if (res.status === 200) {
|
|
|
this.notice = res.data.data?.result;
|
|
|
this.noticeTotal = res.data.data?.total;
|
|
|
}
|
|
|
this.noticeLoading = false;
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
this.noticeLoading = false;
|
|
|
}
|
|
|
},
|
|
|
|
|
|
async read(row) {
|
|
|
try {
|
|
|
this.loading = true;
|
|
|
const res = await axios.get(
|
|
|
`${process.env.VUE_APP_BASE_API}/api/notification/read`,
|
|
|
{
|
|
|
headers: {
|
|
|
Authorization: `Bearer ${getToken()}`,
|
|
|
},
|
|
|
params: {
|
|
|
id: row.id,
|
|
|
},
|
|
|
}
|
|
|
);
|
|
|
if (res.status === 200) {
|
|
|
await this.getNotices();
|
|
|
}
|
|
|
this.loading = false;
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
this.loading = false;
|
|
|
}
|
|
|
},
|
|
|
handle(row) {
|
|
|
try {
|
|
|
const data = row.data;
|
|
|
if (data.from === "ht") {
|
|
|
this.modalUrl = `/${
|
|
|
data.from
|
|
|
}/#/contract/contractList?auth_token=${window.encodeURIComponent(
|
|
|
getToken()
|
|
|
)}&module_name=${data.from}&keyword=${
|
|
|
/\[(.*?)]/.exec(data.title) ? /\[(.*?)]/.exec(data.title)[1] : ""
|
|
|
}&isSinglePage=1`;
|
|
|
} else if (data.from === "oa") {
|
|
|
this.modalUrl = `/${
|
|
|
data.from
|
|
|
}/#/flow/create?auth_token=${window.encodeURIComponent(
|
|
|
getToken()
|
|
|
)}&module_name=${data.from}&flow_id=${
|
|
|
data.other?.flow_id
|
|
|
}&isSinglePage=1`;
|
|
|
}
|
|
|
console.log(this.modalUrl);
|
|
|
this.isShowModal = true;
|
|
|
} catch (err) {
|
|
|
this.$message.warning("未找到流程");
|
|
|
console.error(err);
|
|
|
}
|
|
|
},
|
|
|
},
|
|
|
created() {
|
|
|
this.getWeather();
|
|
|
this.getNotices(true);
|
|
|
this.noticeTimer = setInterval(this.getNotices, 5000)
|
|
|
this.getTotal();
|
|
|
this.getUsualFlows();
|
|
|
this.getAttendance();
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
clearInterval(this.noticeTimer)
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
$btn-colors: linear-gradient(90deg, #d4bbfd 0%, #af7bff 100%),
|
|
|
linear-gradient(90deg, #8dddf7 0%, #3fbde2 100%),
|
|
|
linear-gradient(90deg, #aec1fd 0%, #81a0ea 100%),
|
|
|
linear-gradient(90deg, #f5c0b8 0%, #ee9b98 100%),
|
|
|
linear-gradient(90deg, #ffd2a6 0%, #ffb46d 100%);
|
|
|
::v-deep .el-calendar__header {
|
|
|
display: none;
|
|
|
}
|
|
|
::v-deep .el-input__inner {
|
|
|
border-color: transparent;
|
|
|
border-radius: 10px;
|
|
|
}
|
|
|
::v-deep .el-calendar-table {
|
|
|
border-collapse: separate;
|
|
|
border-spacing: 4px;
|
|
|
}
|
|
|
::v-deep .el-calendar__body table thead th:nth-last-child(1),
|
|
|
::v-deep .el-calendar__body table thead th:nth-last-child(2) {
|
|
|
color: #dd383d;
|
|
|
}
|
|
|
::v-deep .el-calendar-table td,
|
|
|
::v-deep .el-calendar-table tr:first-child td,
|
|
|
::v-deep .el-calendar-table tr td:first-child {
|
|
|
border: none;
|
|
|
}
|
|
|
::v-deep .el-calendar-table__row .current, ::v-deep .el-calendar-table__row .next, ::v-deep .el-calendar-table__row .prev{
|
|
|
min-height: 68px;
|
|
|
position: relative;
|
|
|
}
|
|
|
::v-deep .el-calendar-table .el-calendar-day {
|
|
|
border-radius: 10px;
|
|
|
min-height: 68px;
|
|
|
height: 100%;
|
|
|
transition: all 0.2s;
|
|
|
}
|
|
|
::v-deep .el-calendar-table td.is-selected {
|
|
|
background: var(--theme-color) !important;
|
|
|
color: #fff !important;
|
|
|
border-radius: 10px;
|
|
|
}
|
|
|
::v-deep .el-calendar-table .el-calendar-day:hover {
|
|
|
color: var(--theme-color);
|
|
|
}
|
|
|
::v-deep .el-calendar {
|
|
|
border-radius: 0 0 10px 10px;
|
|
|
}
|
|
|
::v-deep .el-badge__content.is-fixed {
|
|
|
z-index: 1;
|
|
|
}
|
|
|
::v-deep .el-calendar-table .is-today {
|
|
|
|
|
|
&::after {
|
|
|
content: "今";
|
|
|
color: #fff;
|
|
|
background: var(--theme-color);
|
|
|
filter: sepia(0.5);
|
|
|
transform: translate(50%, -50%);
|
|
|
border-radius: 4px;
|
|
|
padding: 2px;
|
|
|
font-size: 10px;
|
|
|
position: absolute;
|
|
|
right: 0;
|
|
|
top: 0;
|
|
|
}
|
|
|
}
|
|
|
.d-flex {
|
|
|
display: flex;
|
|
|
}
|
|
|
.body {
|
|
|
padding: 10px;
|
|
|
}
|
|
|
.mycard {
|
|
|
border-radius: 10px;
|
|
|
filter: drop-shadow(0 0 5px rgba(51, 51, 51, 0.1));
|
|
|
background-color: #ffffff;
|
|
|
padding: 22px;
|
|
|
|
|
|
&__title {
|
|
|
font-size: 20px;
|
|
|
color: #333333;
|
|
|
font-weight: bold;
|
|
|
padding-left: 20px;
|
|
|
position: relative;
|
|
|
|
|
|
&::before {
|
|
|
content: "";
|
|
|
height: 100%;
|
|
|
border-radius: 5px;
|
|
|
background: var(--theme-color);
|
|
|
width: 5px;
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
}
|
|
|
}
|
|
|
&__body {
|
|
|
padding-top: 20px;
|
|
|
}
|
|
|
}
|
|
|
.dashboard {
|
|
|
&-container {
|
|
|
display: flex;
|
|
|
flex-flow: row wrap;
|
|
|
justify-content: space-between;
|
|
|
|
|
|
& > * {
|
|
|
width: calc(50% - 10px);
|
|
|
}
|
|
|
.row {
|
|
|
& > * {
|
|
|
margin-bottom: 20px;
|
|
|
}
|
|
|
}
|
|
|
.weather {
|
|
|
display: flex;
|
|
|
align-items: flex-end;
|
|
|
|
|
|
.center {
|
|
|
margin-left: 20px;
|
|
|
}
|
|
|
.right {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
margin-left: auto;
|
|
|
}
|
|
|
|
|
|
&__icon {
|
|
|
color: var(--theme-color);
|
|
|
font-size: 40px;
|
|
|
}
|
|
|
&__weather {
|
|
|
font-size: 14px;
|
|
|
line-height: 1.5;
|
|
|
text-transform: uppercase;
|
|
|
color: #595959;
|
|
|
text-align: center;
|
|
|
margin-left: 8px;
|
|
|
}
|
|
|
&__temperature {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
justify-content: center;
|
|
|
margin-left: 8px;
|
|
|
|
|
|
.celsius {
|
|
|
& > span:nth-child(1) {
|
|
|
font-size: 44px;
|
|
|
color: #595959;
|
|
|
}
|
|
|
& > span:nth-child(2) {
|
|
|
font-size: 30px;
|
|
|
color: #595959;
|
|
|
}
|
|
|
}
|
|
|
.wind {
|
|
|
background: var(--theme-color);
|
|
|
border-radius: 8px;
|
|
|
font-size: 12px;
|
|
|
padding: 2px 12px;
|
|
|
color: #fff;
|
|
|
text-align: center;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
.calendar {
|
|
|
padding: 0;
|
|
|
|
|
|
&__title {
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
color: #fff;
|
|
|
font-size: 20px;
|
|
|
font-weight: bold;
|
|
|
border-radius: 10px 10px 0 0;
|
|
|
background: var(--theme-color);
|
|
|
padding: 22px;
|
|
|
|
|
|
&::before {
|
|
|
display: none;
|
|
|
}
|
|
|
}
|
|
|
&__body {
|
|
|
background: #fff;
|
|
|
border-radius: 0 0 10px 10px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.flow {
|
|
|
&__body {
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(4, 1fr);
|
|
|
grid-gap: 20px;
|
|
|
|
|
|
& > div {
|
|
|
cursor: pointer;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
justify-content: center;
|
|
|
align-items: center;
|
|
|
}
|
|
|
& > * {
|
|
|
|
|
|
|
|
|
@for $index from 1 through length($btn-colors) {
|
|
|
&:nth-child(#{$index}n) .flow-cover {
|
|
|
background: nth($btn-colors, $index);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.flow-cover {
|
|
|
padding: 10px;
|
|
|
border-radius: 6px;
|
|
|
}
|
|
|
|
|
|
&--icon {
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
align-items: center;
|
|
|
font-size: 30px;
|
|
|
width: 30px !important;
|
|
|
height: 30px !important;
|
|
|
color: #fff;
|
|
|
margin-right: 0 !important;
|
|
|
}
|
|
|
&--name {
|
|
|
color: #5a576f;
|
|
|
font-weight: bold;
|
|
|
font-size: 14px;
|
|
|
padding-top: 20px;
|
|
|
text-align: center;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
.quick-menu {
|
|
|
&__body {
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
& > div {
|
|
|
font-weight: bold;
|
|
|
font-size: 16px;
|
|
|
color: #fff;
|
|
|
padding: 14px 20px;
|
|
|
cursor: pointer;
|
|
|
border-radius: 10px;
|
|
|
margin: 10px 10px 0 0;
|
|
|
// overflow: hidden;
|
|
|
position: relative;
|
|
|
z-index: 3;
|
|
|
|
|
|
&::before {
|
|
|
content: "";
|
|
|
width: 86%;
|
|
|
height: 114%;
|
|
|
background: radial-gradient(
|
|
|
100% 100% at 50% 50%,
|
|
|
#0000 0,
|
|
|
#0000 13%,
|
|
|
#fff2 44%,
|
|
|
#0000 44%
|
|
|
)
|
|
|
no-repeat;
|
|
|
z-index: -1;
|
|
|
position: absolute;
|
|
|
left: -33%;
|
|
|
bottom: -64%;
|
|
|
}
|
|
|
&::after {
|
|
|
content: "";
|
|
|
width: 116%;
|
|
|
height: 152%;
|
|
|
background: radial-gradient(
|
|
|
100% 100% at 50% 50%,
|
|
|
#0000 0,
|
|
|
#0000 13%,
|
|
|
#fff2 44%,
|
|
|
#0000 44%
|
|
|
)
|
|
|
no-repeat;
|
|
|
z-index: -1;
|
|
|
position: absolute;
|
|
|
right: -56%;
|
|
|
bottom: -79%;
|
|
|
}
|
|
|
}
|
|
|
@for $index from 1 through length($btn-colors) {
|
|
|
& > div:nth-child(#{$index}) {
|
|
|
background: nth($btn-colors, $index);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
.todo {
|
|
|
margin-top: 20px;
|
|
|
}
|
|
|
|
|
|
@media (max-width: 992px) {
|
|
|
.body {
|
|
|
padding: 10px;
|
|
|
}
|
|
|
.dashboard {
|
|
|
&-container {
|
|
|
flex-direction: column;
|
|
|
padding: 0;
|
|
|
|
|
|
& > * {
|
|
|
width: 100%;
|
|
|
}
|
|
|
.weather {
|
|
|
display: flex;
|
|
|
|
|
|
&__icon {
|
|
|
font-size: 32px;
|
|
|
}
|
|
|
&__temperature {
|
|
|
.celsius {
|
|
|
& > span:nth-child(1) {
|
|
|
font-size: 32px;
|
|
|
}
|
|
|
& > span:nth-child(2) {
|
|
|
font-size: 20px;
|
|
|
}
|
|
|
}
|
|
|
.wind {
|
|
|
font-size: 11px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.center {
|
|
|
margin-left: 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.todo {
|
|
|
margin-top: 10px;
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
<style lang="scss">
|
|
|
.el-calendar-day:has(.has-attendance)::before{
|
|
|
content: "";
|
|
|
border-radius: 10px;
|
|
|
background: var(--theme-color);
|
|
|
opacity: 0.4;
|
|
|
position: absolute;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
}
|
|
|
.el-calendar-day:has(.has-attendance) .sign-status {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
justify-content: flex-end;
|
|
|
position: relative;
|
|
|
}
|
|
|
.work-overtime {
|
|
|
margin-top: 4px;
|
|
|
color: #fff;
|
|
|
font-size: 10px;
|
|
|
border-radius: 3px;
|
|
|
background: #9f2222;
|
|
|
padding: 2px 4px;
|
|
|
margin-left: auto;
|
|
|
text-align: center;
|
|
|
}
|
|
|
.sign-duty {
|
|
|
margin-top: 4px;
|
|
|
color: #fff;
|
|
|
font-size: 10px;
|
|
|
border-radius: 3px;
|
|
|
background: #f56c6c;
|
|
|
padding: 2px 4px;
|
|
|
margin-left: auto;
|
|
|
text-align: center;
|
|
|
}
|
|
|
.sign-in {
|
|
|
margin-top: 4px;
|
|
|
color: #fff;
|
|
|
font-size: 10px;
|
|
|
border-radius: 3px;
|
|
|
background: var(--theme-color);
|
|
|
padding: 2px 4px;
|
|
|
margin-left: auto;
|
|
|
text-align: center;
|
|
|
}
|
|
|
.sign-out {
|
|
|
margin-top: 4px;
|
|
|
color: #fff;
|
|
|
font-size: 10px;
|
|
|
border-radius: 3px;
|
|
|
background-color: #251f83;
|
|
|
padding: 2px 4px;
|
|
|
margin-left: auto;
|
|
|
text-align: center;
|
|
|
}
|
|
|
.sign-leave {
|
|
|
margin-top: 4px;
|
|
|
color: #fff;
|
|
|
font-size: 8px;
|
|
|
border-radius: 3px;
|
|
|
background-color: #e6a23c;
|
|
|
padding: 2px 4px;
|
|
|
margin-left: auto;
|
|
|
text-align: center;
|
|
|
}
|
|
|
.sign-away {
|
|
|
margin-top: 4px;
|
|
|
color: #fff;
|
|
|
font-size: 8px;
|
|
|
border-radius: 3px;
|
|
|
background-color: #909399;
|
|
|
padding: 2px 4px;
|
|
|
margin-left: auto;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
@media (max-width: 992px) {
|
|
|
.sign-status {
|
|
|
display: block !important;
|
|
|
}
|
|
|
.work-overtime,
|
|
|
.sign-in,
|
|
|
.sign-out,
|
|
|
.sign-leave,
|
|
|
.sign-out {
|
|
|
float: none !important;
|
|
|
}
|
|
|
.el-calendar-table .el-calendar-day {
|
|
|
padding: 2px;
|
|
|
}
|
|
|
}
|
|
|
</style>
|