master
271556543@qq.com 4 years ago
parent b91bbdc6a8
commit 073532ff7c

@ -0,0 +1,25 @@
import request from "@/utils/request";
export function home(params){
return request({
method:'get',
url:'/api/admin/chart/home',
params
})
}
export function income(params){
return request({
method:'get',
url:'/api/admin/chart/income',
params
})
}
export function effct(params){
return request({
method:'get',
url:'/api/admin/chart/effct',
params
})
}

@ -1,9 +0,0 @@
import request from "@/utils/request";
export function home(params){
return request({
method:'get',
url:'/api/admin/chart/home',
params
})
}

@ -31,3 +31,27 @@ export function scheduleDelete(data){
data
})
}
export function scheduleLog(params){
return request({
method:'get',
url:'/api/admin/schedule/schedule-log',
params
})
}
export function scheduleLogShow(params){
return request({
method:'get',
url:'/api/admin/schedule/schedule-log-show',
params
})
}
export function scheduleHome(params){
return request({
method:'get',
url:'/api/admin/schedule/schedule-home',
params
})
}

@ -0,0 +1,369 @@
<script>
export default {
props:{
type:{
type:String,
default:"normal"
//"normal" "form"
},
//
width:{
type:Number,
default:55
},
isShow:{
type:Boolean,
default:false
},
title:{
type:String,
default: ''
},
form:{
type:Array,
default:()=>[]
},
rules:{
type:Object,
default:()=>{
return {}
}
},
okText:{
type:String
}
},
data() {
return {
res:{}
}
},
methods: {
formItemContentRender(item){
let content;
switch(item.type){
case "input":
content = (
<el-input
placeholder={`请输入${item.label}`}
value={this.res[item.prop]}
style={item.style ?? {'width':'300px'}}
on={{['input']:e=>{
this.$set(this.res,item.prop,e)
//this.res[item.prop] = e
}}}>
</el-input>
)
break;
case "select":
content = (
<el-select
placeholder={`请选择${item.label}`}
value={this.res[item.prop]}
style={item.style ?? {'width':'300px'}}
on={{['change']:e => this.res[item.prop] = e}}>
{
item.data.map(item => {
return (
<el-option label={item.options?.label ? item[item.options?.label] : item.label}
value={item.options?.value ? item[item.options?.value] : item.id}>
</el-option>
)
})
}
</el-select>
)
break;
case "timePicker":
content = (
<el-time-picker
value-format={item.valueFormat ?? "hh:mm:ss"}
placeholder={`请选择${item.label}`}
value={this.res[item.prop]}
picker-options={item.options}
on={{['change']:e => this.res[item.prop] = e}}>
</el-time-picker>
)
break;
case "datePicker":
content = (
<el-date-picker
type={item.dateType ?? 'date'}
value-format={item.valueFormat ?? "yyyy-MM-dd"}
value={this.res[item.prop]}
placeholder={`请选择${item.label}`}
picker-options={item.options}
on={{['change']:e => this.res[item.prop] = e}}>
</el-date-picker>
)
break;
case "inputNumber":
content = (
<el-input-number
precision={item.precision}
control={false}
placeholder={`请输入${item.label}`}
value={this.res[item.prop]}
on={{['change']:e => this.res[item.prop] = e}}>
</el-input-number>
)
break;
}
return content
},
footerRender(){
if(this.type === 'form'){
return (
<div>
<Button ghost type="primary" on-click={this.reset}>重置</Button>
<Button type="primary" on-click={this.submit}>{this.okText || '确定'}</Button>
</div>
)
}
if(this.type === 'normal'){
return (
<div>
<Button ghost type="primary" on-click={()=>{this.$emit('update:isShow',false)}}>取消</Button>
<Button type="primary" on-click={()=>{this.$emit('on-ok')}}>{this.okText || '确定'}</Button>
</div>
)
}
},
showChange(e){
this.$emit('update:isShow',e)
},
validate(){
return new Promise((resolve,reject)=>{
this.$refs['elForm'].validate().then(res=>{
if(res){
resolve(res)
}else{
reject(res)
}
}).catch(err=>{
reject(err)
this.$Message.warning({
content:'请填写完整信息',
duration:1
})
})
})
},
reset(){
this.$emit('reset')
if(this.type === 'normal'){
return
}
this.$refs['elForm'].resetFields()
},
clearValidate(){
this.$emit('clearValidate')
if(this.type === 'normal'){
return
}
this.$refs['elForm'].clearValidate()
},
submit(){
if(this.type === 'normal'){
return
}
this.$refs['elForm'].validate().then(res=>{
if(res){
this.$emit('submit',this.res)
}
}).catch(err=>{
this.$Message.warning({
content:'请填写完整信息',
duration:1
})
})
},
okClick(){
this.$emit('on-ok')
}
},
created() {
this.form.forEach(item => {
Object.defineProperty(this.res,item.prop,{
value:item.value,
enumerable:true,
writable:true,
configurable:true
})
})
},
watch:{
isShow(val){
this.$emit('show-change',val)
if(!val && this.type === 'form'){
this.reset()
}
},
},
render(h) {
/*
type='form' slot:
extraFormTop
extraFormBottom
{表单名}
type='normal' slot:
normalContent
footer slot:
footerContent
*/
const {res,okText,okClick,formItemContentRender,footerRender,width,type,$scopedSlots,rules,form,showChange,isShow,title} = this
return (
<Modal
ok-text={okText}
class-name={'vertical-center-modal'}
width={width}
title={title}
value={isShow}
on={{['on-visible-change']:showChange,['on-ok']:okClick}}
scopedSlots={{
default(){
if(type === "form"){
return (
<el-form
style={title.length === 0 ? {'margin-top':'32px'} : {}}
ref="elForm"
props={{
model:res,
rules
}}>
{ form.map(item => {
if(!item.hidden){
if($scopedSlots[item.prop]){
return (
<el-form-item label={item.label} prop={item.prop}>
{ $scopedSlots[item.prop]() }
</el-form-item>
)
}else{
return (
<el-form-item label={item.label} prop={item.prop}>
{ formItemContentRender(item) }
</el-form-item>
)
}
}
}) }
</el-form>
)
}else{
return (
<div
style={title.length === 0 ? {'margin-top':'32px'} : {}}>
{$scopedSlots.default ? $scopedSlots.default() : ''}
</div>
)
}
},
header(){
if($scopedSlots.headerContent){
return $scopedSlots.headerContent()
}
},
footer(){
{
if(type === 'form' || type === 'normal') return ($scopedSlots.footerContent ? $scopedSlots.footerContent() : footerRender())
}
}
}}>
</Modal>
)
}
}
</script>
<style lang="scss">
.xy-table-item-label{
width: 140px;
text-align: right;
}
.xy-table-item-min{
position: relative;
&::after{
z-index: 1;
position: absolute;
right: 0;
top: 0;
content:'(分钟)'
}
::v-deep .el-input__clear{
position: relative;
right: 46px;
z-index: 2;
}
}
.xy-table-item-price{
position: relative;
&::after{
z-index: 1;
position: absolute;
right: 0;
top: 0;
content:'(元)'
}
::v-deep .el-input__clear{
position: relative;
right: 30px;
z-index: 2;
}
}
.xy-table-item-price-wan{
position: relative;
&::after{
position: absolute;
right: 0;
top: 0;
content:'(万元)'
}
::v-deep .el-input__clear{
position: relative;
right: 46px;
z-index: 2;
}
}
.vertical-center-modal{
display: flex;
align-items: center;
justify-content: center;
.ivu-modal{
top: 0;
}
}
.ivu-modal-body{
max-height: 65vh !important;
min-height: 300px;
overflow: scroll;
}
.xy-table-item{
display: flex;
align-items: center;
padding-right: 80px;
&-label{
padding: 0 20px;
}
&-content{
}
}
.el-form-item{
flex-shrink: 0;
flex-basis: 50%;
}
.el-form-item__error{
white-space: nowrap;
word-break: keep-all !important;
top: 100% !important;
left: calc(100% - 80px) !important;
transform: translateX(-100%);
}
</style>

@ -113,6 +113,9 @@ export default {
let tableHeight = clientHeight - lxHeader_height - topHeight - paginationHeight - 20 - 25;
that.tableHeight = tableHeight;
},
doLayout(){
this.$refs.table.doLayout()
},
deleteClick(row) {
this.$emit('delete', row)
},
@ -236,6 +239,8 @@ export default {
if (item.customFn) {
return (
<el-table-column
fixed={item.fixed ?? false}
render-header={item.renderHeader ?? undefined}
align={item.align ?? 'center'}
sortable={item.sortable ?? false}
width={item.width ?? 'auto'}
@ -254,12 +259,14 @@ export default {
//
return (
<el-table-column
render-header={item.renderHeader ?? undefined}
header-align={item.headerAlign ?? 'center'}
label={item.label}>
{item.multiHd.map((item1, index1) => {
if (item1.customFn) {
return (
<el-table-column
render-header={item1.renderHeader ?? undefined}
align={item1.align ?? 'center'}
header-align={item1.headerAlign ?? 'center'}
label={item1.label}
@ -276,6 +283,7 @@ export default {
} else {
return (
<el-table-column
render-header={item1.renderHeader ?? undefined}
fixed={item1.fixed ?? false}
align={item1.align ?? 'center'}
header-align={item1.headerAlign ?? 'center'}
@ -296,6 +304,7 @@ export default {
//
return (
<el-table-column
render-header={item.renderHeader ?? undefined}
fixed={item.fixed ?? false}
formatter={item.formatter}
width={item.width ?? 'auto'}

@ -2,24 +2,34 @@
<div class="serve-detail">
<xy-dialog :is-show.sync="isShow">
<template>
<div class="serve-detail__title">
服务时间
</div>
<div class="serve-detail__time-value">
12:00 ~ 16:00
<div style="display: flex;align-items: center">
<div class="serve-detail__title">
服务时间
</div>
<div class="serve-detail__time-value" style="padding-left: 20px;">
{{time}}
</div>
</div>
<div class="serve-detail__title">
签到打卡
</div>
<xy-table :height="300" :is-page="false" :table-item="columns" :list="detail">
<template v-slot:btns>
<el-table-column align="center" width="80" label="照片查看" header-align="center">
<template v-slot:default="scope">
<Poptip transfer placement="top" >
<template v-slot:default>
<Button type="primary" size="small" @click="setPicList(scope.row)"></Button>
</template>
<div class="serve-detail__title">
过程打卡
</div>
<div class="serve-detail__title">
签退打卡
</div>
<template v-slot:content>
<template v-for="item in scope.row.upload_list">
<el-image :preview-src-list="picList" :src="item.upload.url" fit="contain" style="height: 200px;"></el-image>
</template>
</template>
</Poptip>
</template>
</el-table-column>
</template>
</xy-table>
</template>
<template v-slot:footerContent>
@ -30,18 +40,69 @@
</template>
<script>
import {scheduleLog} from '@/api/schedule'
export default {
data() {
return {
id:'',
time:'',
isShow:false,
picList:[],
detail:[],
columns:[
{
prop:'type',
label:'类型',
width: 140,
formatter:(cell,data,val)=>{
switch (val){
case 1:
return '签到'
break;
case 2:
return '过程打卡'
break;
case 3:
return '签退'
break;
case 4:
return '更新定位'
break;
default:
return val;
}
}
},
{
prop:'address',
label:'定位地址',
minWidth:220,
align:'left'
}
]
}
},
methods: {
setPicList(row){
this.picList = row.upload_list.map(item => item.upload?.url)
},
async getDetail(){
let res = await scheduleLog({id:this.id})
console.log(res)
this.detail = res
}
},
watch:{
isShow(val){
if(val){
this.getDetail()
}else{
this.id = ''
}
}
}
}
</script>

@ -5,14 +5,22 @@
<div slot="content"></div>
<slot>
<div>
<Input v-model="select.keyword" placeholder="关键字搜索" style="width: 200px; margin-right: 10px"/>
<Button style="margin-left: 10px" type="primary" @click="select.page = 1,getList">查询</Button>
<el-date-picker
size="small"
v-model="date"
type="month"
placeholder="选择月"
style="width: 180px;"
@change="datePick">
</el-date-picker>
<Button style="margin-left: 10px" type="primary" @click="select.page = 1,getList()">查询</Button>
</div>
</slot>
</lx-header>
</div>
<xy-table
ref="xyTable"
:default-expand-all="false"
row-key="name"
:total="total"
@ -32,10 +40,13 @@ import {parseTime} from "@/utils"
export default {
data() {
return {
date:'',
select:{
page:1,
page_size:10,
keyword:''
keyword:'',
start_date:'',
end_date:''
},
types:[],
@ -53,40 +64,19 @@ export default {
align:'right'
}
],
table:[
{
type:'expand',
label:'详情',
width: 80,
expandFn:(props)=>{
return (
<div style={{'width':'400px','margin-left':'40px'}}>
<xy-table
defaultExpandAll={false}
table-item={this.dataTable}
list={props.row.data}
is-page={false}
height={260}
scopedSlots={{
btns:()=>{
return ''
}
}}>
</xy-table>
</div>
)
}
},
table:[],
baseTable:[
{
label:'姓名',
width:260,
fixed: 'left',
width:140,
prop:'name'
},
{
label:'小计',
minWidth: 160,
width: 80,
align:'right',
fixed:'right',
customFn:(row)=>{
let total = 0;
row.data.map(item => {
@ -103,6 +93,22 @@ export default {
}
},
methods: {
getDate(year,month){
let d = new Date(year,month,0)
return d.getDate()
},
datePick(e){
if(!e){
return
}
let start = parseTime(e,'{y}-{m}-{d}')
let end = parseTime(new Date(e.getFullYear(),e.getMonth()+1,0),'{y}-{m}-{d}')
this.select.start_date = start
this.select.end_date = end
},
async getList(){
const res = await getList(this.select)
this.tableArr = res.map((item,index) => {
@ -110,9 +116,47 @@ export default {
})
this.total = res.length ?? 0
this.list = res
this.table = []
let date = this.getDate(new Date(this.select.start_date).getFullYear(),new Date(this.select.start_date).getMonth()+1)
let header = []
const getHeader = (h) => {
header = []
for(let i = 1;i <= date;i ++){
header.push(h('div',{style:{width:'100px',flex:'none',borderRight:'2px solid #EBEEF5'}},`${i}`))
}
return header
}
let temp = {
minWidth:date*100 + 10,
renderHeader:(h)=>{
return h('div',{style:{display:'flex',width:'100%'}},getHeader(h))
},
customFn:(row)=>{
return (
<div style={{display:'flex'}}>
{
row.data.map(item => {
return (
<div style={{width:'100px',flex:'none',borderRight:'2px solid #EBEEF5',textAlign:'right',padding:'0 4px'}}>{item.money}</div>
)
})
}
</div>
)
}
}
this.table.push(temp)
this.table.push(...this.baseTable)
this.$nextTick(()=>{
this.$refs['xyTable'].doLayout()
})
},
},
mounted() {
this.date = new Date()
this.select.start_date = parseTime(new Date(new Date().getFullYear(),new Date().getMonth(),1),'{y}-{m}-{d}')
this.select.end_date = parseTime(new Date(new Date().getFullYear(),new Date().getMonth()+1,0),'{y}-{m}-{d}')
this.getList()
}
}

@ -19,7 +19,7 @@
<template v-slot:btns>
<el-table-column fixed="right" label="操作" width="68" header-align="center" align="center">
<template v-slot:default="scope">
<Button size="small" type="primary" @click="detail(scope.row),$refs['detailServe'].isShow=true"></Button>
<Button size="small" type="primary" @click="detail(scope)"></Button>
</template>
</el-table-column>
</template>
@ -67,7 +67,7 @@ export default {
width: 170,
customFn:(row) => {
return (
<div>{parseTime(new Date(row.start_time),'{h}:{i}')}~{parseTime(new Date(row.start_time),'{h}:{i}')}</div>
<div>{parseTime(new Date(row.start_time),'{h}:{i}')}~{parseTime(new Date(row.end_time),'{h}:{i}')}</div>
)
}
},
@ -111,10 +111,11 @@ export default {
}
},
methods: {
detail(row){
console.log(row)
detail(scope){
this.$refs['detailServe'].time = `${parseTime(new Date(scope.row.start_time),'{h}:{i}')} ~ ${parseTime(new Date(scope.row.end_time),'{h}:{i}')}`
this.$refs['detailServe'].id = scope.row.id
this.$refs['detailServe'].isShow = true
},
async getList(){
const res = await getList(this.select)
this.total = res.total

@ -4,54 +4,93 @@
<div slot="content"></div>
<slot>
<div>
<div class="switch" style="margin-bottom: 8px">
<div v-for="item in types" :class="{'switch-item-active':item.id === select.type}" class="switch-item"
@click="select.type = item.id">{{ item.name }}
</div>
</div>
<el-select v-model="select.product_type_id" size="small" style="width: 200px">
<el-option v-for="item in types" :label="item.name" :value="item.id"></el-option>
</el-select>
<div class="switch" style="margin-bottom: 8px">
<div v-for="item in areas" :class="{'switch-item-active':item.id === select.area}" class="switch-item"
@click="select.area = item.id">{{ item.value }}
</div>
<el-select v-model="select.area_id" size="small" style="width: 200px;margin-left: 10px;">
<el-option v-for="item in areas" :label="item.value" :value="item.id"></el-option>
</el-select>
<el-date-picker
type="month"
size="small"
v-model="select.month"
value-format="yyyy-MM"
style="width: 200px;margin-left: 10px;">
</el-date-picker>
<el-button size="small" type="primary" @click="getSchedule" style="margin-left: 10px;">查询</el-button>
</div>
<div class="select">{{select.month}} {{ areaFormatter(select.area_id) }} {{ typeFormatter(select.product_type_id) }}</div>
<div style="display: flex;justify-content: space-between;margin-bottom: 10px;" v-if="totals">
<div style="display:flex;text-align: center">
<template v-for="(value,key) of totals.left">
<Card style="margin-right: 6px">
<div>{{ value }}</div>
<div>{{ key }}</div>
</Card>
</template>
</div>
<div class="switch">
<div v-for="item in months()" :class="{'switch-item-active':item === select.month}" class="switch-item"
@click="select.month = item">{{ item }}
</div>
<div style="display:flex;text-align: center">
<template v-for="(value,key) of totals.right">
<Card style="margin-left: 6px">
<div>{{ value }}</div>
<div>{{ key }}</div>
</Card>
</template>
</div>
</div>
</slot>
</lx-header>
<div class="schedule-content">
<div class="schedule-content-select">{{select.month}} {{ areaFormatter(select.area) }} {{ typeFormatter(select.type) }}</div>
<div style="display: flex;justify-content: space-between;margin-bottom: 10px;">
<div style="display:flex;text-align: center">
<template v-for="(value,key) of totals.left">
<Card style="margin-right: 6px">
<div>{{ value }}</div>
<div>{{ key }}</div>
</Card>
</template>
</div>
<div
style="overflow:auto;height: 100%">
<div style="height: 40px"></div>
<template v-for="item in lists">
<div class="schedule-content-item">
<div class="schedule-content-item__date">
<div class="schedule-content-item__date--left">{{item.date}} {{item.week}}</div>
<div class="schedule-content-item__date--right">
<span>总上门人次</span>
<span>{{item.has_total}}</span>
<span style="margin-left: 10px">待上门人次</span>
<span>{{item.wait_total === 0 ? '✔' : item.wait_total}}</span>
</div>
</div>
<div style="display:flex;text-align: center">
<template v-for="(value,key) of totals.right">
<Card style="margin-left: 6px">
<div>{{ value }}</div>
<div>{{ key }}</div>
</Card>
</template>
</div>
</div>
<template v-if="item.detail.length > 0">
<div class="schedule-content-item__schedule">
<template v-for="item1 in item.detail">
<Poptip transfer trigger="hover">
<template v-slot:default>
<div class="schedule-content-item__schedule-item">
<div class="schedule-content-item__schedule-item--title">
<span>{{timeFormat(item1.start_time)}}</span>
<span>~</span>
<span>{{timeFormat(item1.end_time)}}</span>
</div>
<div class="schedule-content-item__schedule-item--name">{{item1.customer.name}}</div>
</div>
</template>
<div class="infinite-list" :infinite-scroll-disabled="scrollDisable" v-infinite-scroll="load" :infinite-scroll-delay="500" style="overflow:auto;height: 200px">
<template v-for="i in count">
<div>
{{ i }}
<template v-slot:content>
<div>
<span style="font-weight: 600">状态</span>
<span :style="{'color':colorFormat(item1.status)}">{{statusFormat(item1.status)}}</span>
</div>
</template>
</Poptip>
</template>
</div>
</template>
<template v-else>
<div class="schedule-content-item__schedule--none">暂无排班</div>
</template>
</div>
</template>
</div>
@ -60,13 +99,14 @@
</template>
<script>
import {parseTime} from '@/utils'
import {scheduleHome} from '@/api/schedule'
import {getList as typeList} from '@/api/productType'
import {getparameter} from '@/api/system/dictionary'
export default {
data() {
return {
count:0,
scrollDisable:false,
types: [],
@ -78,25 +118,13 @@ export default {
}
return temp
},
totals:{
left:{
'上门需求':200,
'服务时长':4000,
'已安排':189,
'未安排':11
},
right:{
'护理人员':30,
'可提供服务时长':5000,
'已排时长':3800,
'空闲时长':1200
}
},
totals:'',//
lists:[],
select: {
type: '',
area: '',
month: `${new Date().getMonth() + 1}`.padStart(2, '0')
product_type_id: '',
area_id: '',
month: parseTime(new Date(),'{y}-{m}'),
}
}
},
@ -105,28 +133,40 @@ export default {
var that = this;
var clientHeight = document.documentElement.clientHeight
var lxHeader_height = document.querySelector('.v-header').getBoundingClientRect().height; //
var paginationHeight = 37; //
var topHeight = 50; //
let contentHeight = clientHeight - lxHeader_height - topHeight - paginationHeight - 20;
let contentHeight = clientHeight - lxHeader_height - topHeight - 20 - 125;
document.querySelector('.schedule-content').style.height = `${contentHeight}px`
},
load () {
console.log(11)
this.count += 2
if(this.count > 50){
this.scrollDisable = true
async getSchedule(){
let res = await scheduleHome(this.select)
this.lists = res.list
this.totals = {
left:{
'上门需求':res.statistics?.need_order_total ?? 0,
'服务时长':res.statistics?.server_timelength ?? 0,
'已安排':res.statistics?.use_order_total ?? 0,
'未安排':res.statistics?.wait_order_total ?? 0
},
right:{
'护理人员':res.statistics?.wait_order_total.nurse_total ?? 0,
'可提供服务时长':res.statistics?.nurse_can_timelength,
'已排时长':res.statistics?.nurse_use_timelength ?? 0,
'空闲时长':res.statistics?.nurse_stock_timelength ?? 0
}
}
},
async getTypes(){
const res = await typeList({page:1,page_size:999},false)
this.types = res.data
this.select.product_type_id = res.data[0].id
},
async getAreas(){
const res = await getparameter({number:'serveArea'})
const res = await getparameter({number:'changzhou'})
this.areas = res.detail
this.select.area_id = res.detail[0].id
}
},
computed: {
@ -144,88 +184,132 @@ export default {
})[0]?.value || ''
}
},
isNowMonth() {
return function (month) {
if (month === `${new Date().getMonth() + 1}`.padStart(2, '0')) {
return '(当月)'
timeFormat(){
return function (date,format = '{h}:{i}'){
return parseTime(new Date(date),format)
}
},
statusFormat(){
return function (status){
switch (status){
case 0:
return "未开始"
break;
case 1:
return "进行中"
break;
case 2:
return "已完成"
break;
default:
return status
}
}
},
colorFormat(){
return function (status){
switch (status){
case 0:
return "red"
break;
case 1:
return "green"
break;
case 2:
return "blue"
break;
default:
return status
}
}
}
},
mounted() {
this.getTypes()
this.getAreas()
this.initLoad()
async mounted() {
await this.getTypes()
await this.getAreas()
await this.initLoad()
await this.getSchedule()
}
}
</script>
<style lang="scss" scoped>
@import '../../styles/index.scss';
.switch {
display: flex;
&-item {
flex: 1;
text-align: center;
letter-spacing: 2px;
color: rgb(100, 100, 100);
.select{
letter-spacing: 1px;
font-size: 16px;
text-align: center;
font-weight: 600;
}
.schedule-content{
&-item{
border: 1px $primaryColor solid;
background: #fff;
border: 1px solid rgb(210, 210, 210);
padding: 2px 0;
&-active {
border: none;
overflow: hidden;
animation: btn-click 800ms forwards ease-out;
position: relative;
&::after{
content: '';
width: 300px;
height: 300px;
border-radius: 100%;
background: rgba(180,180,180,0.4);
animation: ripple 800ms forwards;
transform: translateX(-50%);
position: absolute;
top: -300px;
left: 50%;
}
}
@keyframes ripple {
from{
opacity: 1;
border-radius: 0 6px 6px 6px;
margin-bottom: 60px;
position: relative;
&__date{
display: flex;
position: absolute;
top: -30px;
left: -1px;
&--left{
height: 30px;
background: $primaryColor;
color: #fff;
line-height: 30px;
border-radius: 6px 6px 0 0 ;
padding: 0 14px;
}
to{
opacity: 0;
top: 0;
&--right{
height: 30px;
line-height: 30px;
font-size: 13px;
padding: 0 10px;
}
}
@keyframes btn-click {
from{
}
to{
&__schedule{
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
padding: 8px 8px;
&-item{
font-size: 12px;
text-align: center;
color: #fff;
border-radius: 4px;
background: $primaryColor;
padding: 5px 8px;
margin-right: 8px;
&:hover{
animation: hover 100ms linear forwards;
}
@keyframes hover {
to{
transform: scale(1.1,1.1);
filter: drop-shadow(0 0 8px #de342c);
}
}
}
}
}
& > div:nth-child(-n+2) {
border-right: none;
}
}
.schedule-content {
&-select{
font-size: 15px;
text-align: center;
font-weight: 600;
&__schedule--none{
line-height: 60px;
text-align: center;
}
}
}
</style>

@ -1,25 +1,58 @@
<template>
<div>
<lx-header icon="md-apps" style="margin-bottom: 10px; border: 0px; margin-top: 15px" text="收入统计">
<div slot="content"></div>
<slot>
<div>
<el-date-picker
type="month"
size="small"
v-model="select.month"
value-format="yyyy-MM"
style="width: 200px;">
</el-date-picker>
<el-button size="small" type="primary" style="margin-left: 10px;" @click="getIncome"></el-button>
</div>
</slot>
</lx-header>
<div style="display: flex;margin-top: 20px">
<doughnutChart></doughnutChart>
<barChart></barChart>
<doughnutChart :data="data.product_type_list"></doughnutChart>
<barChart :data="data.product"></barChart>
</div>
</div>
</template>
<script>
import doughnutChart from './components/doughnutChart'
import barChart from "./components/barChart";
import {income} from '@/api/chart'
import doughnutChart from './incomeComponents/doughnutChart'
import barChart from "./incomeComponents/barChart";
export default {
components:{
doughnutChart,
barChart
},
data() {
return {}
return {
select:{
month:`${new Date().getFullYear()}-${new Date().getMonth()+1}`
},
data:{},
}
},
methods: {},
methods: {
async getIncome(){
let res = await income(this.select)
console.log(res)
this.data = res
}
},
mounted() {
this.getIncome()
}
}
</script>

@ -1,19 +1,19 @@
<template>
<div class="box">
<div>
<div class="box" v-if="data">
<div style="border-bottom: 2px solid rgba(200,200,200,0.7);padding-bottom: 20px">
<i class="el-icon-data-line"></i>
<span>产品收入统计</span>
<span style="font-weight: 600;padding: 0 10px">产品收入统计</span>
</div>
<div id="bar-chart"></div>
<div class="detail">
<div>长护险重症: 100000</div>
<div>长护险中度: 150000</div>
<div>残疾人照护: 200000</div>
<div> 80+老人照护: 400000</div>
<div>自营单次: 5000</div>
<div>自营月度4次包: 6000</div>
<template v-for="item in data">
<div>{{item.name}} {{item.total}}</div>
</template>
<div>
总计 {{total()}}
</div>
</div>
</div>
</template>
@ -25,16 +25,17 @@ require('echarts/theme/macarons') // echarts theme
export default {
props:{
data:{
type:Array,
default:()=>[]
}
},
data() {
return {
chart: null
}
},
mounted() {
this.$nextTick(() => {
this.init()
})
},
beforeDestroy() {
if (!this.chart) {
return
@ -42,8 +43,20 @@ export default {
this.chart.dispose()
this.chart = null
},
watch:{
data:{
handler(){
this.$nextTick(() => {
this.init()
})
},
deep:true
}
},
methods: {
init() {
let dataName = this.data.map(item => item.name)
let dataVal = this.data.map(item => item.total)
this.chart = echarts.init(document.getElementById('bar-chart'))
this.chart.setOption({
tooltip: {
@ -77,12 +90,12 @@ export default {
width: '2'
}
},
data: ['自营月度4次包', '自营单次', '80岁+老人照护', '残疾人照护', '长护险中度', '长护险重症']
data: dataName
},
series: [
{
type: 'bar',
data: [6003, 5041, 4237, 3751, 2001, 1096],
data: dataVal,
itemStyle: {
normal: {
color: '#009DFF',
@ -92,6 +105,17 @@ export default {
]
})
}
},
computed:{
total(){
return function (){
let total = 0;
this.data.forEach(item => {
total += item.total
})
return total
}
}
}
}
</script>

@ -1,24 +1,18 @@
<template>
<div class="box">
<div>
<div class="box" v-if="data">
<div style="border-bottom: 2px solid rgba(200,200,200,0.7);padding-bottom: 20px">
<i class="el-icon-coin"></i>
<span>板块收入统计</span>
<span style="font-weight: 600;padding: 0 10px">板块收入统计</span>
</div>
<div id="doughnut-chart"/>
<div class="detail">
<template v-for="item in data">
<div>{{item.name}} {{item.total}}</div>
</template>
<div>
长护险: 10000
</div>
<div>
80+老人照护: 10000
</div>
<div>
自营商业: 10000
</div>
<div>
总计: 30000
总计: {{ total() }}
</div>
</div>
</div>
@ -32,15 +26,26 @@ require('echarts/theme/macarons') // echarts theme
export default {
props:{
data:{
type:Array,
default:()=>[]
}
},
data() {
return {
chart: null
}
},
mounted() {
this.$nextTick(() => {
this.init()
})
watch:{
data:{
handler(){
this.$nextTick(() => {
this.init()
})
},
deep:true
}
},
beforeDestroy() {
if (!this.chart) {
@ -51,6 +56,19 @@ export default {
},
methods: {
init() {
let colors = ['#00A82A','#70e1f5','#ffd194','#FF6B6B','#6E48AA','#4B1248']
let data = this.data.map((item,index) => {
return {
value:item.total,
name:item.name,
itemStyle: {
normal: {
color: colors[(index+1)%6]
},
},
}
})
this.chart = echarts.init(document.getElementById('doughnut-chart'))
this.chart.setOption({
tooltip: {
@ -84,48 +102,22 @@ export default {
labelLine: {
show: false
},
data: [
{
value: 10408,
name: '长护险',
itemStyle: {
normal: {
color: '#00A82A'
},
},
},
{
value: 20000,
name: '残疾人照护',
itemStyle: {
normal: {
color: '#FF8522'
},
},
},
{
value: 9622,
name: '80岁+老人照护',
itemStyle: {
normal: {
color: '#2B50FF'
},
},
},
{
value: 4842,
name: '自营商业',
itemStyle: {
normal: {
color: '#F2A300'
},
},
},
]
data
}
]
})
}
},
computed:{
total(){
return function (){
let total = 0;
this.data.forEach(item => {
total += item.total
})
return total
}
},
}
}
</script>

@ -1,17 +1,61 @@
<template>
<div>
<lx-header icon="md-apps" style="margin-bottom: 10px; border: 0px; margin-top: 15px" text="人效统计">
<div slot="content"></div>
<slot>
<div>
<el-date-picker
type="month"
size="small"
v-model="select.month"
value-format="yyyy-MM"
style="width: 200px;">
</el-date-picker>
<el-button size="small" type="primary" style="margin-left: 10px;" @click="getEffct"></el-button>
</div>
</slot>
</lx-header>
<div style="display: flex;margin-top: 20px">
<doughnutChart :data="data.product_type_list"></doughnutChart>
<barChart :data="data.area"></barChart>
</div>
</div>
</template>
<script>
import {effct} from '@/api/chart'
import doughnutChart from './peopleComponents/doughnutChart'
import barChart from "./peopleComponents/barChart";
export default {
components:{
doughnutChart,
barChart
},
data() {
return {}
return {
select:{
month:`${new Date().getFullYear()}-${new Date().getMonth()+1}`
},
data:{},
}
},
methods: {},
methods: {
async getEffct(){
let res = await effct(this.select)
console.log(res)
this.data = res
}
},
mounted() {
this.getEffct()
}
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,145 @@
<template>
<div class="box" v-if="data">
<div style="border-bottom: 2px solid rgba(200,200,200,0.7);padding-bottom: 20px">
<i class="el-icon-data-line"></i>
<span style="font-weight: 600;padding: 0 10px">区域人效统计</span>
</div>
<div id="bar-chart"></div>
<div class="detail">
<template v-for="item in data">
<div>{{item.value}} {{item.total.toFixed(2)}}小时/</div>
</template>
<div>
总计 {{total().toFixed(2)}}小时/
</div>
</div>
</div>
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
export default {
props:{
data:{
type:Array,
default:()=>[]
}
},
data() {
return {
chart: null
}
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
watch:{
data:{
handler(){
this.$nextTick(() => {
this.init()
})
},
deep:true
}
},
methods: {
init() {
let dataName = this.data.map(item => item.value)
let dataVal = this.data.map(item => item.total.toFixed(2))
this.chart = echarts.init(document.getElementById('bar-chart'))
this.chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {},
grid: {
top: '6%',
left: '3%',
right: '6%',
bottom: '12%',
containLabel: true
},
xAxis: {
type: 'value',
axisLabel: {
color: '#B7B9BF'
},
axisLine: {
show: false,
}
},
yAxis: {
type: 'category',
axisLine: {
lineStyle: {
color: '#B7B9BF',
width: '2'
}
},
data: dataName
},
series: [
{
type: 'bar',
data: dataVal,
itemStyle: {
normal: {
color: '#009DFF',
},
},
}
]
})
}
},
computed:{
total(){
return function (){
let total = 0;
this.data.forEach(item => {
total += item.total
})
return total
}
}
}
}
</script>
<style lang="scss" scoped>
.box {
flex: 1;
background: #fff;
border-radius: 10px;
padding: 20px;
#bar-chart {
box-sizing: border-box;
min-height: 240px;
}
.detail{
&>div{
border-bottom: 1px rgba(210,210,210,0.7) solid;
padding: 6px 8px;
margin: 0 20px;
}
}
}
</style>

@ -0,0 +1,148 @@
<template>
<div class="box" v-if="data">
<div style="border-bottom: 2px solid rgba(200,200,200,0.7);padding-bottom: 20px">
<i class="el-icon-coin"></i>
<span style="font-weight: 600;padding: 0 10px">板块人效统计</span>
</div>
<div id="doughnut-chart"/>
<div class="detail">
<template v-for="item in data">
<div>{{item.name}} {{item.total.toFixed(2)}}小时/</div>
</template>
<div>
总计: {{ total().toFixed(2) }}小时/
</div>
</div>
</div>
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
export default {
props:{
data:{
type:Array,
default:()=>[]
}
},
data() {
return {
chart: null
}
},
watch:{
data:{
handler(){
this.$nextTick(() => {
this.init()
})
},
deep:true
}
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
init() {
let colors = ['#00A82A','#70e1f5','#ffd194','#FF6B6B','#6E48AA','#4B1248']
let data = this.data.map((item,index) => {
return {
value:item.total.toFixed(2),
name:item.name,
itemStyle: {
normal: {
color: colors[(index+1)%6]
},
},
}
})
this.chart = echarts.init(document.getElementById('doughnut-chart'))
this.chart.setOption({
tooltip: {
trigger: 'item'
},
legend: {
top: '3%',
left: 'center'
},
series: [
{
type: 'pie',
radius: ['46%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '15',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data
}
]
})
}
},
computed:{
total(){
return function (){
let total = 0;
this.data.forEach(item => {
total += item.total
})
return total
}
},
}
}
</script>
<style lang="scss" scoped>
.box {
flex: 1;
background: #fff;
border-radius: 10px;
padding: 20px;
margin-right: 40px;
#doughnut-chart {
box-sizing: border-box;
min-height: 240px;
}
.detail{
&>div{
border-bottom: 1px rgba(210,210,210,0.7) solid;
padding: 6px 8px;
margin: 0 20px;
}
}
}
</style>
Loading…
Cancel
Save