|
@@ -59,6 +59,7 @@
|
|
:options="supplierOptions"
|
|
:options="supplierOptions"
|
|
size="small"
|
|
size="small"
|
|
style="width: 150px"
|
|
style="width: 150px"
|
|
|
|
+ placeholder="请选择人力供应商"
|
|
>
|
|
>
|
|
</t-select>
|
|
</t-select>
|
|
</div>
|
|
</div>
|
|
@@ -70,14 +71,18 @@
|
|
<div class="num-show flex items-center justify-around">
|
|
<div class="num-show flex items-center justify-around">
|
|
<div class="desc">
|
|
<div class="desc">
|
|
<div class="label">实施工程师(人)</div>
|
|
<div class="label">实施工程师(人)</div>
|
|
- <div class="value">172</div>
|
|
|
|
|
|
+ <div class="value">{{ ssgcsNum }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="desc">
|
|
<div class="desc">
|
|
<div class="label">区域协调人(人)</div>
|
|
<div class="label">区域协调人(人)</div>
|
|
- <div class="value">39</div>
|
|
|
|
|
|
+ <div class="value">{{ qyxtrNum }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- <div class="desc-text">覆盖4个大区:北京、天津、武汉、广州</div>
|
|
|
|
|
|
+ <div class="desc-text"
|
|
|
|
+ >覆盖{{ regionOptions?.length }}个大区:{{
|
|
|
|
+ regionOptions.map((item) => item.label).join('、')
|
|
|
|
+ }}</div
|
|
|
|
+ >
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@@ -87,6 +92,14 @@
|
|
>
|
|
>
|
|
<div class="title">
|
|
<div class="title">
|
|
<span class="label">项目角色待调配额盘点</span>
|
|
<span class="label">项目角色待调配额盘点</span>
|
|
|
|
+ <t-select
|
|
|
|
+ v-model="regionId"
|
|
|
|
+ :options="regionOptions"
|
|
|
|
+ size="small"
|
|
|
|
+ style="width: 150px"
|
|
|
|
+ placeholder="请选择大区"
|
|
|
|
+ >
|
|
|
|
+ </t-select>
|
|
</div>
|
|
</div>
|
|
<div class="box4">
|
|
<div class="box4">
|
|
<div class="charts-box">
|
|
<div class="charts-box">
|
|
@@ -110,8 +123,12 @@
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="desc-text">
|
|
<div class="desc-text">
|
|
- <p>大区内同业务类型待划拨派单数量:3个</p>
|
|
|
|
- <p>当前大区覆盖城市:2个</p>
|
|
|
|
|
|
+ <p
|
|
|
|
+ >大区内同业务类型待划拨派单数量:{{
|
|
|
|
+ result4?.projectWait
|
|
|
|
+ }}个</p
|
|
|
|
+ >
|
|
|
|
+ <p>当前大区覆盖城市:{{ result4?.regionCities }}个</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@@ -121,9 +138,14 @@
|
|
</div>
|
|
</div>
|
|
<div class="bar-box flex items-center">
|
|
<div class="bar-box flex items-center">
|
|
<div class="process-box">
|
|
<div class="process-box">
|
|
- <div class="process" :style="{ width: '20%' }"></div>
|
|
|
|
|
|
+ <div
|
|
|
|
+ class="process"
|
|
|
|
+ :style="{ width: (result5 || 0) * 100 + '%' }"
|
|
|
|
+ ></div>
|
|
</div>
|
|
</div>
|
|
- <span class="process-text m-l-10px">20%</span>
|
|
|
|
|
|
+ <span class="process-text m-l-10px">{{
|
|
|
|
+ (result5 || 0) * 100 + '%'
|
|
|
|
+ }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card m-t-15px" style="height: 80px">
|
|
<div class="card m-t-15px" style="height: 80px">
|
|
@@ -132,9 +154,14 @@
|
|
</div>
|
|
</div>
|
|
<div class="bar-box flex items-center">
|
|
<div class="bar-box flex items-center">
|
|
<div class="process-box">
|
|
<div class="process-box">
|
|
- <div class="process" :style="{ width: '90%' }"></div>
|
|
|
|
|
|
+ <div
|
|
|
|
+ class="process"
|
|
|
|
+ :style="{ width: (result6 || 0) * 100 + '%' }"
|
|
|
|
+ ></div>
|
|
</div>
|
|
</div>
|
|
- <span class="process-text m-l-10px">90%</span>
|
|
|
|
|
|
+ <span class="process-text m-l-10px">{{
|
|
|
|
+ (result5 || 0) * 100 + '%'
|
|
|
|
+ }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@@ -182,6 +209,8 @@ import {
|
|
personNumAnalysis,
|
|
personNumAnalysis,
|
|
serviceServiceList,
|
|
serviceServiceList,
|
|
} from '@/api/report';
|
|
} from '@/api/report';
|
|
|
|
+const ssgcsNum = ref('');
|
|
|
|
+const qyxtrNum = ref('');
|
|
const curTimeRange = ref([]);
|
|
const curTimeRange = ref([]);
|
|
const serviceOptions = ref([]);
|
|
const serviceOptions = ref([]);
|
|
const timeParams = computed(() => {
|
|
const timeParams = computed(() => {
|
|
@@ -206,7 +235,7 @@ const {
|
|
const {
|
|
const {
|
|
data: result3,
|
|
data: result3,
|
|
loading: loading3,
|
|
loading: loading3,
|
|
- run: run3,
|
|
|
|
|
|
+ runAsync: run3,
|
|
} = useRequest(supplierRoleAnalysis); //人力供应商项目角色人员分布
|
|
} = useRequest(supplierRoleAnalysis); //人力供应商项目角色人员分布
|
|
|
|
|
|
const { data: regionList, runAsync: runGetRegionList } =
|
|
const { data: regionList, runAsync: runGetRegionList } =
|
|
@@ -215,7 +244,7 @@ const { data: regionList, runAsync: runGetRegionList } =
|
|
const {
|
|
const {
|
|
data: result4,
|
|
data: result4,
|
|
loading: loading4,
|
|
loading: loading4,
|
|
- runAsync: run4,
|
|
|
|
|
|
+ run: run4,
|
|
} = useRequest(projectRoleAnalysis); //项目角色待调配配额盘点
|
|
} = useRequest(projectRoleAnalysis); //项目角色待调配配额盘点
|
|
|
|
|
|
const {
|
|
const {
|
|
@@ -253,6 +282,9 @@ watch(serviceId, (serviceUnitId) => {
|
|
run1({ serviceUnitId });
|
|
run1({ serviceUnitId });
|
|
run2({ serviceUnitId }).then((res) => {
|
|
run2({ serviceUnitId }).then((res) => {
|
|
if (!supplierId.value) {
|
|
if (!supplierId.value) {
|
|
|
|
+ if (res.supplierDistribution?.length) {
|
|
|
|
+ supplierId.value = res.supplierDistribution[0].id;
|
|
|
|
+ }
|
|
//赋值,默认选择第一个供应商
|
|
//赋值,默认选择第一个供应商
|
|
//todo ...
|
|
//todo ...
|
|
}
|
|
}
|
|
@@ -265,17 +297,47 @@ watch(serviceId, (serviceUnitId) => {
|
|
|
|
|
|
const supplierId = ref('');
|
|
const supplierId = ref('');
|
|
const supplierOptions = computed(() => {
|
|
const supplierOptions = computed(() => {
|
|
|
|
+ return (result2.value?.supplierDistribution || []).map((item) => {
|
|
|
|
+ item.label = item.name;
|
|
|
|
+ item.value = item.id;
|
|
|
|
+ return item;
|
|
|
|
+ });
|
|
//与result2相关,转换数据即可
|
|
//与result2相关,转换数据即可
|
|
return [];
|
|
return [];
|
|
});
|
|
});
|
|
const regionId = ref('');
|
|
const regionId = ref('');
|
|
const regionOptions = computed(() => {
|
|
const regionOptions = computed(() => {
|
|
- //与result4相关,转换数据即可
|
|
|
|
- return [];
|
|
|
|
|
|
+ return (regionList.value || []).map((item) => {
|
|
|
|
+ item.label = item.region_name;
|
|
|
|
+ item.value = item.region_id;
|
|
|
|
+ return item;
|
|
|
|
+ });
|
|
});
|
|
});
|
|
-watch('supplierId', (supplierId) => {
|
|
|
|
- run3({ serviceUnitId: serviceId.value, supplierId });
|
|
|
|
- runGetRegionList({ serviceUnitId: serviceId.value, supplierId });
|
|
|
|
|
|
+watch(supplierId, (supplierId) => {
|
|
|
|
+ run3({ serviceUnitId: serviceId.value, supplierId }).then((res) => {
|
|
|
|
+ let obj1 = res.find(
|
|
|
|
+ (item) => item.NAME === '实施工程师' || item.name === '实施工程师'
|
|
|
|
+ );
|
|
|
|
+ let obj2 = res.find(
|
|
|
|
+ (item) => item.NAME === '区域协调人' || item.name === '区域协调人'
|
|
|
|
+ );
|
|
|
|
+ obj1 && (ssgcsNum.value = obj1.count);
|
|
|
|
+ obj2 && (qyxtrNum.value = obj2.count);
|
|
|
|
+ });
|
|
|
|
+ runGetRegionList({ serviceUnitId: serviceId.value, supplierId }).then(
|
|
|
|
+ (res) => {
|
|
|
|
+ if (res && res.length) {
|
|
|
|
+ regionId.value = res[0].region_id;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+});
|
|
|
|
+watch(regionId, (regionId) => {
|
|
|
|
+ run4({
|
|
|
|
+ serviceUnitId: serviceId.value,
|
|
|
|
+ supplierId: supplierId.value,
|
|
|
|
+ regionId,
|
|
|
|
+ });
|
|
});
|
|
});
|
|
|
|
|
|
const options1 = computed(() => {
|
|
const options1 = computed(() => {
|
|
@@ -285,77 +347,89 @@ const options1 = computed(() => {
|
|
radius: '80%',
|
|
radius: '80%',
|
|
});
|
|
});
|
|
});
|
|
});
|
|
-const options2 = createRingPieOption(
|
|
|
|
- {
|
|
|
|
- data: [
|
|
|
|
- { name: '阳光雨露', value: 26 },
|
|
|
|
- { name: '软通智服', value: 12 },
|
|
|
|
- { name: 'AAAA', value: 13 },
|
|
|
|
- { name: 'BBBB', value: 12 },
|
|
|
|
- { name: 'CCCC', value: 12 },
|
|
|
|
- { name: 'DDDD', value: 15 },
|
|
|
|
- { name: 'EEEE', value: 42 },
|
|
|
|
- { name: 'FFFF', value: 102 },
|
|
|
|
- { name: 'GGGG', value: 12 },
|
|
|
|
- { name: 'HHHH', value: 72 },
|
|
|
|
- ],
|
|
|
|
- title: '派单数',
|
|
|
|
- center: ['50%', '25%'],
|
|
|
|
- seriesName: '数量',
|
|
|
|
- radius: [40, 60],
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- legend: {
|
|
|
|
- // type: 'scroll',
|
|
|
|
- orient: 'horizontal',
|
|
|
|
- top: null,
|
|
|
|
- right: null,
|
|
|
|
- bottom: '0%',
|
|
|
|
- left: 'center',
|
|
|
|
|
|
+
|
|
|
|
+const options2 = computed(() => {
|
|
|
|
+ const supplierDistribution = result2?.supplierDistribution || [];
|
|
|
|
+ return createRingPieOption(
|
|
|
|
+ {
|
|
|
|
+ data: supplierDistribution.map((item) => {
|
|
|
|
+ item.value = item.count;
|
|
|
|
+ return item;
|
|
|
|
+ }),
|
|
|
|
+ title: '派单数',
|
|
|
|
+ center: ['50%', '25%'],
|
|
|
|
+ seriesName: '数量',
|
|
|
|
+ radius: [40, 60],
|
|
},
|
|
},
|
|
- }
|
|
|
|
-);
|
|
|
|
|
|
+ {
|
|
|
|
+ legend: {
|
|
|
|
+ // type: 'scroll',
|
|
|
|
+ orient: 'horizontal',
|
|
|
|
+ top: null,
|
|
|
|
+ right: null,
|
|
|
|
+ bottom: '0%',
|
|
|
|
+ left: 'center',
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+});
|
|
|
|
|
|
-const options3 = createCakePieOption(
|
|
|
|
- {
|
|
|
|
- data: [
|
|
|
|
- { name: '实施工程师', value: 172 },
|
|
|
|
- { name: '区域协调人', value: 39 },
|
|
|
|
- ],
|
|
|
|
- radius: [0, 50],
|
|
|
|
- center: ['50%', '50%'],
|
|
|
|
- seriesName: '角色分布',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- legend: {
|
|
|
|
- show: false,
|
|
|
|
|
|
+const options3 = computed(() => {
|
|
|
|
+ let data = (result3.value || []).map((item) => {
|
|
|
|
+ item.value = item.count;
|
|
|
|
+ item.name = item.NAME || item.name;
|
|
|
|
+ return item;
|
|
|
|
+ });
|
|
|
|
+ return createCakePieOption(
|
|
|
|
+ {
|
|
|
|
+ data: data,
|
|
|
|
+ radius: [0, 50],
|
|
|
|
+ center: ['50%', '50%'],
|
|
|
|
+ seriesName: '角色分布',
|
|
},
|
|
},
|
|
- // legend: {
|
|
|
|
- // orient: 'horizontal',
|
|
|
|
- // top: '',
|
|
|
|
- // right: '',
|
|
|
|
- // bottom: '1%',
|
|
|
|
- // left: 'center',
|
|
|
|
- // },
|
|
|
|
- }
|
|
|
|
-);
|
|
|
|
|
|
+ {
|
|
|
|
+ legend: {
|
|
|
|
+ show: false,
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+});
|
|
|
|
|
|
-const options41 = createWaterBallOption({
|
|
|
|
- data: 65 / 100,
|
|
|
|
- title: '剩130配额',
|
|
|
|
- radius: '80%',
|
|
|
|
|
|
+const options41 = computed(() => {
|
|
|
|
+ let projectRoleQuota = result4.value?.projectRoleQuota || {};
|
|
|
|
+ return createWaterBallOption({
|
|
|
|
+ data: projectRoleQuota.effectDistributed / projectRoleQuota.effectQuota,
|
|
|
|
+ title: `剩${
|
|
|
|
+ projectRoleQuota.effectQuota - projectRoleQuota.effectDistributed
|
|
|
|
+ }配额`,
|
|
|
|
+ radius: '80%',
|
|
|
|
+ });
|
|
});
|
|
});
|
|
-const options42 = createWaterBallOption({
|
|
|
|
- data: 35 / 100,
|
|
|
|
- title: '剩34配额',
|
|
|
|
- radius: '80%',
|
|
|
|
- color: '35, 195, 67',
|
|
|
|
|
|
+const options42 = computed(() => {
|
|
|
|
+ let projectRoleQuota = result4.value?.projectRoleQuota || {};
|
|
|
|
+ return createWaterBallOption({
|
|
|
|
+ data:
|
|
|
|
+ projectRoleQuota.coordinatorDistributed /
|
|
|
|
+ projectRoleQuota.coordinatorQuota,
|
|
|
|
+ title: `剩${
|
|
|
|
+ projectRoleQuota.coordinatorQuota -
|
|
|
|
+ projectRoleQuota.coordinatorDistributed
|
|
|
|
+ }配额`,
|
|
|
|
+ radius: '80%',
|
|
|
|
+ color: '35, 195, 67',
|
|
|
|
+ });
|
|
});
|
|
});
|
|
-const options43 = createWaterBallOption({
|
|
|
|
- data: 55 / 100,
|
|
|
|
- title: '剩14配额',
|
|
|
|
- radius: '80%',
|
|
|
|
- color: '255, 154, 46',
|
|
|
|
|
|
+const options43 = computed(() => {
|
|
|
|
+ let projectRoleQuota = result4.value?.projectRoleQuota || {};
|
|
|
|
+ return createWaterBallOption({
|
|
|
|
+ data:
|
|
|
|
+ projectRoleQuota.assistantDistributed / projectRoleQuota.assistantQuota,
|
|
|
|
+ title: `剩${
|
|
|
|
+ projectRoleQuota.assistantQuota - projectRoleQuota.assistantDistributed
|
|
|
|
+ }配额`,
|
|
|
|
+ radius: '80%',
|
|
|
|
+ color: '255, 154, 46',
|
|
|
|
+ });
|
|
});
|
|
});
|
|
const options7 = computed(() => {
|
|
const options7 = computed(() => {
|
|
return createCakePieOption(
|
|
return createCakePieOption(
|
|
@@ -403,6 +477,7 @@ const options8 = computed(() => {
|
|
data: data,
|
|
data: data,
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
+ console.log(xData, sData);
|
|
return createStackingBarOption(
|
|
return createStackingBarOption(
|
|
{
|
|
{
|
|
xData: xData,
|
|
xData: xData,
|