Browse Source

“新增首页可视化图纸”

master
zhouhaibin 4 months ago
parent
commit
b9aacff047
  1. 1
      package.json
  2. 6
      src/main.ts
  3. 90
      src/views/dashboard/workbench/components/DonutChart.vue
  4. 68
      src/views/dashboard/workbench/components/DonutChartByMoney.vue
  5. 51
      src/views/dashboard/workbench/components/PieChart.vue
  6. 163
      src/views/dashboard/workbench/index.vue
  7. 3
      src/views/projectLib/projectPlan/planinfoFileDetail.vue
  8. 193
      src/views/projectSummary/planSummary/indeForDashboard.vue
  9. 13
      src/views/projectSummary/planSummary/index.vue

1
package.json

@ -100,6 +100,7 @@
"tinymce": "^5.10.7",
"unocss": "0.53.4",
"vditor": "^3.9.4",
"vue-echarts": "^6.6.0",
"vue": "^3.3.4",
"vue-i18n": "^9.6.4",
"vue-json-pretty": "^2.2.4",

6
src/main.ts

@ -16,6 +16,9 @@ import { initAppConfigStore } from '@/logics/initAppConfig';
import { router, setupRouter } from '@/router';
import { setupRouterGuard } from '@/router/guard';
import { setupStore } from '@/store';
// echart图表
import "echarts"
import ECharts from "vue-echarts"
import App from './App.vue';
@ -59,7 +62,8 @@ async function bootstrap() {
// https://next.router.vuejs.org/api/#isready
// await router.isReady();
// echart图表
app.component('v-chart', ECharts)
app.mount('#app');
}

90
src/views/dashboard/workbench/components/DonutChart.vue

@ -0,0 +1,90 @@
<template>
<v-chart :option="option" theme="auto" :autoresize="true" style="width: 100%; height: 200px" />
</template>
<script lang="ts" name="DonutChart" setup>
import { ref, reactive } from 'vue'
let receivingParameter = defineProps(["fininshNum", "unfininshNum", "name"])
let option = reactive({})
option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
// data: [
// '',
// ''
// ],
left: 'left',
// orient: 'vertical',
},
series: [
// {
// name: 'Access From',
// type: 'pie',
// selectedMode: 'single',
// radius: [0, '30%'],
// label: {
// position: 'inner',
// fontSize: 14
// },
// labelLine: {
// show: false
// },
// },
{
name: receivingParameter.name,
type: 'pie',
radius: ['30%', '60%'],
labelLine: {
length: 10
},
label: {
// formatter: '{a|{a}}{abg|}\n{hr|}\n {b|{b}}{c} {per|{d}%} ',
formatter: ' {b|{b}:}{per|{d}%} \n{hr|}\n{c|{c}}',//dcb,aname
backgroundColor: '#F6F8FC',
borderColor: '#8C8D8E',
borderWidth: 1,
borderRadius: 4,
rich: {
a: {
color: '#6E7079',
lineHeight: 22,
align: 'center'
},
hr: {
borderColor: '#8C8D8E',
width: '100%',
borderWidth: 1,
height: 0
},
b: {
color: '#4C5058',
fontSize: 14,
// fontWeight: 'bold',
// lineHeight: 33
},
per: {
color: '#fff',
backgroundColor: '#4C5058',
padding: [3, 4],
borderRadius: 4
},
c: {
align: 'center' // c
}
}
},
data: [
{ value: receivingParameter.fininshNum, name: '已完成', itemStyle: { color: '#00A2E8', } },//
{ value: receivingParameter.unfininshNum, name: '未完成', itemStyle: { color: '#DCE0E6', } },
],
}
]
}
</script>
<style></style>

68
src/views/dashboard/workbench/components/DonutChartByMoney.vue

@ -0,0 +1,68 @@
<template>
<v-chart :option="option" theme="auto" :autoresize="true" style="width: 100%; height: 200px" />
</template>
<script lang="ts" name="DonutChart" setup>
import { ref, reactive } from 'vue'
let receivingParameter = defineProps(["fininshNum", "unfininshNum", "name"])
let option = reactive({})
option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
// data: [
// '',
// ''
// ],
left: 'left',
// orient: 'vertical',
},
series: [
// {
// name: 'Access From',
// type: 'pie',
// selectedMode: 'single',
// radius: [0, '30%'],
// label: {
// position: 'inner',
// fontSize: 14
// },
// labelLine: {
// show: false
// },
// },
{
name: receivingParameter.name,
type: 'pie',
radius: ['50%', '80%'],
label: {
alignTo: 'edge',
formatter: '{name|{b}}\n{time|{c}元}\n{value|{d}%}',
minMargin: 5,
edgeDistance: 10,
lineHeight: 15,
rich: {
time: {
fontSize: 10,
color: '#999'
}
}
},
labelLine: {
length: 10,
length2: 0,
maxSurfaceAngle: 80
},
data: [
{ value: receivingParameter.fininshNum, name: '已支付', itemStyle: { color: '#53E3CC', } },
{ value: receivingParameter.unfininshNum, name: '未支付', itemStyle: { color: '#CC0033 ', } },
],
}
]
}
</script>
<style></style>

51
src/views/dashboard/workbench/components/PieChart.vue

@ -0,0 +1,51 @@
<template>
<v-chart :option="option" theme="auto" :autoresize="true" style="width: 100%; height: 200px" />
</template>
<script lang="ts" name="PieChart" setup>
import { ref, reactive } from 'vue'
let receivingParameter = defineProps(["data"])
let option = reactive({})
option = {
tooltip: {
trigger: 'item'
},
legend: {
left: 'left',
orient: 'vertical',
},
series: [
{
name: '项目状态',
type: 'pie',
radius: '90%',
data: receivingParameter.data,
// data: [
// { value: 1048, name: '' },
// { value: 735, name: '' },
// { value: 580, name: '' },
// { value: 484, name: '' },
// { value: 300, name: '' },
// { value: 300, name: '' },
// { value: 1, name: '' }
// ],
label: {
show: false,
position: 'center'
},
// emphasis: {
// itemStyle: {
// shadowBlur: 10,
// shadowOffsetX: 0,
// shadowColor: 'rgba(0, 0, 0, 0.5)'
// }
// }
}
]
};
</script>
<style></style>

163
src/views/dashboard/workbench/index.vue

@ -1,38 +1,145 @@
<template>
<PageWrapper>
<template #headerContent> <WorkbenchHeader /> </template>
<div class="lg:flex">
<div class="lg:w-7/10 w-full !mr-4 enter-y">
<template #headerContent>
<WorkbenchHeader />
</template>
<div >
<ProjectCard :loading="loading" class="enter-y" />
<!-- <DynamicInfo :loading="loading" class="!my-4 enter-y" /> -->
</div>
<div class="lg:w-3/10 w-full enter-y">
<!-- <QuickNav :loading="loading" class="enter-y" /> -->
<Card class="!my-4 enter-y" :loading="loading">
<img class="xl:h-50 h-30 mx-auto" src="../../../assets/svg/illustration.svg" />
</Card>
<!-- <SaleRadar :loading="loading" class="enter-y" /> -->
</div>
<div class="card-container">
<a-tabs v-model:activeKey="activeKey" type="card">
<a-tab-pane key="1" tab="总进度">
<div style="background-color: #ececec; padding: 20px">
<a-row :gutter="16">
<a-col :span="8">
<a-card title="项目总进度" :bordered="false">
<!-- <el-progress type="circle" :percentage="25" :stroke-width="10" /> -->
<DonutChart :fininshNum="data.xiangmZJD.fininshNum" :unfininshNum="data.xiangmZJD.unfininshNum"
:name="'项目总进度'" />
</a-card>
</a-col>
<a-col :span="8">
<a-card title="资金支付情况" :bordered="false">
<DonutChartByMoney :fininshNum="data.xiangmuZJ.fininshNum" :unfininshNum="data.xiangmuZJ.unfininshNum"
:name="'资金支付情况'" />
</a-card>
</a-col>
<a-col :span="8">
<a-card title="项目状态" :bordered="false">
<PieChart :data="data.xiangmuZT" />
</a-card>
</a-col>
</a-row>
</div>
<div>
<planSummary />
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="所属改革任务">
<div style="background-color: #ececec; padding: 20px">
<a-row :gutter="16">
<a-col :span="8" v-for="(item, index) in data.SSGGRW" :key="index">
<a-card :title="item.name" :bordered="false">
<!-- <el-progress type="circle" :percentage="25" :stroke-width="10" /> -->
<DonutChart :fininshNum="item.fininshNum" :unfininshNum="item.unfininshNum" :name="item.name" />
</a-card>
</a-col>
</a-row>
</div>
</a-tab-pane>
<a-tab-pane key="3" tab="行政区域">
<div style="background-color: #ececec; padding: 20px">
<a-row :gutter="16">
<a-col :span="8" v-for="(item, index) in data.XXQY" :key="index">
<a-card :title="item.name" :bordered="false">
<!-- <el-progress type="circle" :percentage="25" :stroke-width="10" /> -->
<DonutChart :fininshNum="item.fininshNum" :unfininshNum="item.unfininshNum" :name="item.name" />
</a-card>
</a-col>
</a-row>
</div>
</a-tab-pane>
<a-tab-pane key="4" tab="单位属性">
<div style="background-color: #ececec; padding: 20px">
<a-row :gutter="16">
<a-col :span="8" v-for="(item, index) in data.DWSX" :key="index">
<a-card :title="item.name" :bordered="false">
<!-- <el-progress type="circle" :percentage="25" :stroke-width="10" /> -->
<DonutChart :fininshNum="item.fininshNum" :unfininshNum="item.unfininshNum" :name="item.name" />
</a-card>
</a-col>
</a-row>
</div>
</a-tab-pane>
</a-tabs>
</div>
<div>
<planSummary/>
</div>
</PageWrapper>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { Card } from 'ant-design-vue';
import { PageWrapper } from '@/components/Page';
import WorkbenchHeader from './components/WorkbenchHeader.vue';
import ProjectCard from './components/ProjectCard.vue';
import QuickNav from './components/QuickNav.vue';
import DynamicInfo from './components/DynamicInfo.vue';
import SaleRadar from './components/SaleRadar.vue';
import planSummary from '@/views/projectSummary/planSummary/index.vue';
const loading = ref(true);
setTimeout(() => {
loading.value = false;
}, 1500);
import { ref, reactive } from 'vue';
import { PageWrapper } from '@/components/Page';
import WorkbenchHeader from './components/WorkbenchHeader.vue';
import DonutChart from './components/DonutChart.vue';
import PieChart from './components/PieChart.vue';
import ProjectCard from './components/ProjectCard.vue';
import DonutChartByMoney from './components/DonutChartByMoney.vue';
import planSummary from '@/views/projectSummary/planSummary/indeForDashboard.vue';
const loading = ref(true);
const activeKey = ref('1');
const data = reactive({
xiangmZJD: {
fininshNum: 40,
unfininshNum: 10,
},
xiangmuZJ: {
fininshNum: 400000,
unfininshNum: 230000,
},
xiangmuZT: [
{ value: 1048, name: '待入库' },
{ value: 735, name: '入库中' },
{ value: 580, name: '已入库' },
{ value: 484, name: '计划审批中' },
{ value: 300, name: '计划执行中' },
{ value: 300, name: '已归档' },
{ value: 12, name: '已出库' }
],
SSGGRW: [
{ name: "2+N紧密型城市医疗集团建设", fininshNum: 100, unfininshNum: 30 },
{ name: "2+9+9+N县域医共体建设", fininshNum: 140, unfininshNum: 20 },
{ name: "市县公立医院妇幼能力建设", fininshNum: 140, unfininshNum: 120 },
{ name: "高水平县级医院建设 ", fininshNum: 140, unfininshNum: 90 },
{ name: "打造长三角市域医学高地", fininshNum: 140, unfininshNum: 90 },
{ name: "公立医院院前急救与院内救治服务融合发展", fininshNum: 170, unfininshNum: 90 },
{ name: "医共体下三医联动改革", fininshNum: 170, unfininshNum: 90 },
{ name: "智慧医院服务能力提档升级", fininshNum: 100, unfininshNum: 30 },
{ name: "数字健康大脑建设", fininshNum: 140, unfininshNum: 270 },
{ name: "舒心就医", fininshNum: 140, unfininshNum: 270 },
{ name: "中医药固本培元", fininshNum: 140, unfininshNum: 210 },
{ name: "公立医院运营管理", fininshNum: 140, unfininshNum: 80 },
{ name: "公立医院党建全行业引领改革工程 ", fininshNum: 140, unfininshNum: 40 },
{ name: "高质量临床重点专科建设 ", fininshNum: 140, unfininshNum: 80 },
],
XXQY: [
{ name: "南浔区", fininshNum: 100, unfininshNum: 30 },
{ name: "吴兴区", fininshNum: 140, unfininshNum: 20 },
{ name: "市本级", fininshNum: 140, unfininshNum: 120 },
{ name: "安吉县", fininshNum: 140, unfininshNum: 90 },
{ name: "德清县", fininshNum: 140, unfininshNum: 90 },
{ name: "长兴县", fininshNum: 170, unfininshNum: 90 },
],
DWSX: [
{ name: "卫生行政部门", fininshNum: 1000, unfininshNum: 3000 },
{ name: "医疗机构 ", fininshNum: 1400, unfininshNum: 2000 },
]
})
setTimeout(() => {
loading.value = false;
}, 1500);
</script>

3
src/views/projectLib/projectPlan/planinfoFileDetail.vue

@ -28,10 +28,11 @@ onMounted(async () => {
// processName.value =await getProcessName(dataTo.planinfoid)
})
async function init(data) {
processName.value =await getProcessName({pid:data.planinfoid})
planinfoid.value = data.planinfoid
taskName.value = data.taskName
isfinish.value = data.isfinish
processName.value =await getProcessName({pid:data.planinfoid})
}

193
src/views/projectSummary/planSummary/indeForDashboard.vue

@ -0,0 +1,193 @@
<template>
<PageWrapper dense>
<!--引用表格-->
<BasicTable @register="registerTable">
<template v-for="(item, index) in planSummary" v-slot:[item.dataIndex]="{ record }">
<div v-if="record[item.dataIndex]">
<span>{{ record[item.dataIndex].taskName }}</span>
<Progress type="circle" :percent="record[item.dataIndex].percent" :size="20" :strokeColor="record[item.dataIndex].color" @click="handleViewPlanDetail(record[item.dataIndex].id, record[item.dataIndex].color)"></Progress>
</div>
</template>
<!-- <template #phaseNumber0="{ record }">
<div v-if="record.phaseNumber0">
<span>{{ record.phaseNumber0.taskName }}</span>
<Progress type="circle" :percent="record.phaseNumber0.percent" :size="20" :strokeColor="record.phaseNumber0.color"></Progress>
</div>
</template>
<template #phaseNumber1="{ record }">
<div v-if="record.phaseNumber1">
<span>{{ record.phaseNumber1.taskName }}</span>
<Progress type="circle" :percent="record.phaseNumber1.percent" :size="20" :strokeColor="record.phaseNumber1.color" ></Progress>
</div>
</template>
<template #phaseNumber2="{ record }">
<div v-if="record.phaseNumber2">
<span>{{ record.phaseNumber2.taskName }}</span>
<Progress type="circle" :percent="record.phaseNumber2.percent" :size="20" :strokeColor="record.phaseNumber2.color" ></Progress>
</div>
</template>
<template #phaseNumber3="{ record }">
<div v-if="record.phaseNumber3">
<span>{{ record.phaseNumber3.taskName }}</span>
<Progress type="circle" :percent="record.phaseNumber3.percent" :size="20" :strokeColor="record.phaseNumber3.color" ></Progress>
</div>
</template>
<template #phaseNumber4="{ record }">
<div v-if="record.phaseNumber4">
<span>{{ record.phaseNumber4.taskName }}</span>
<Progress type="circle" :percent="record.phaseNumber4.percent" :size="20" :strokeColor="record.phaseNumber4.color" ></Progress>
</div>
</template>
<template #phaseNumber5="{ record }">
<div v-if="record.phaseNumber5">
<span>{{ record.phaseNumber5.taskName }}</span>
<Progress type="circle" :percent="record.phaseNumber5.percent" :size="20" :strokeColor="record.phaseNumber5.color" ></Progress>
</div>
</template>
<template #phaseNumber6="{ record }">
<div v-if="record.phaseNumber6">
<span>{{ record.phaseNumber6.taskName }}</span>
<Progress type="circle" :percent="record.phaseNumber6.percent" :size="20" :strokeColor="record.phaseNumber6.color" ></Progress>
</div>
</template> -->
</BasicTable>
<!-- <BasicModal @register="registeViewPlanDetail" title="项目计划详情" width="1200px" :showOkBtn="false">
<viewPlanDetail :projectId="projectId" :projectStage="projectStage" />
</BasicModal>
<BasicModal @register="registerProjectPlan" title="发起项目计划审批" width="1200px" :showOkBtn="false"
:showCancelBtn="false">
<addPlan :type="type" :projectid="projectId" @close="closeProjectPlanModal()" />
</BasicModal> -->
</PageWrapper>
</template>
<script lang="ts" name="indeForDashboard" setup>
//ts
import { ref, onMounted } from 'vue';
import { BasicTable, useTable } from '@/components/Table';
import { PageWrapper } from '@/components/Page';
import { Progress } from 'ant-design-vue';
import { searchFormSchema } from '@/views/projectLib/projectInfo/projectInfo.data';
import { planSummaryColumn } from '@/views/projectSummary/planSummary/planSummary.data';
import { getplanSummary } from '@/views/projectSummary/planSummary/planSummary.api'
onMounted(async () => {
})
let planSummary = ref<Array<any>>([]);
const [registerTable, { setColumns }] = useTable({
api: getplanSummary,
columns: planSummaryColumn,
rowKey:"projectName",
showIndexColumn:false,
useSearchForm: false,
// actionColumn: {
// width: 140,
// title: '',
// dataIndex: 'action',
// slots: { customRender: 'action' },
// },
afterFetch: (data) => {
planSummary.value.pop()
let temp = JSON.parse(JSON.stringify(planSummaryColumn))
data.forEach(item => {
Object.entries(item).forEach(([key, value]) => {
if (key.includes("phaseNumber")) {
let keyExists = true;
Object.entries(temp).forEach(([keytemp, valuetemp]) => {
if (valuetemp.dataIndex == key) {
keyExists = false
return
}
})
if (keyExists) {
temp.push({
title: key.replace("phaseNumber", "阶段"),
dataIndex: key,
slots: { customRender: key },
align:'left'
})
planSummary.value.push({
title: key,
dataIndex: key,
})
}
}
});
})
console.log("lanSummary.valu", planSummary.value);
setColumns(temp)
},
//
formConfig: {
schemas: searchFormSchema,
}
});
function handleViewPlanDetail(projectId: string, color: string) {
console.log("handleViewPlanDetail", projectId, color);
}
</script>
<style scoped>
.timeline {
display: flex;
width: 100%;
margin-bottom: 100px;
.lineitem {
transform: translateX(50%);
width: 25%;
}
}
::v-deep .el-timeline-item__tail {
border-left: none;
width: 100%;
border-top: 2px solid #e4e7ed;
position: absolute;
top: 6px;
}
::v-deep .el-timeline-item__wrapper {
padding-left: 0;
position: absolute;
top: 20px;
transform: translateX(-50%);
text-align: center;
}
::v-deep .el-timeline-item__timestamp {
font-size: 14px;
}
.nested-timeline {
margin-left: 20px;
border-left: 1px dashed #ccc;
padding-left: 20px;
}
.nested-timeline-item {
margin-bottom: 10px;
}
::v-deep .ant-table-expanded-row {
height: auto !important;
/* 其他样式 */
}
</style>

13
src/views/projectSummary/planSummary/index.vue

@ -69,21 +69,14 @@
<script lang="ts" name="planSummary" setup>
//ts
import { ref, onMounted } from 'vue';
import { ActionItem, BasicTable, TableAction, useTable } from '@/components/Table';
import { BasicTable, useTable } from '@/components/Table';
import { PageWrapper } from '@/components/Page';
import { Progress } from 'ant-design-vue';
import { useModal, BasicModal } from '@/components/Modal';
import addPlan from '@/views/projectLib/projectPlan/addPlan.vue'
import viewPlanDetail from "@/views/projectLib/projectPlan/viewPlanDetail.vue";
import { isShowByRoles } from '@/views/projectLib/projectInfo/projectInfo.api';
import { columns, searchFormSchema } from '@/views/projectLib/projectInfo/projectInfo.data';
import { searchFormSchema } from '@/views/projectLib/projectInfo/projectInfo.data';
import { planSummaryColumn } from '@/views/projectSummary/planSummary/planSummary.data';
import { getplanSummary } from '@/views/projectSummary/planSummary/planSummary.api'
import { projectPlanPageList } from '@/views/projectLib/projectPlan/projectPlan.api';
import { useUserStore } from '@/store/modules/user';
import { color } from 'echarts';
onMounted(async () => {
})

Loading…
Cancel
Save