浏览代码

feat:提报汇总

wangzs 3 月之前
父节点
当前提交
227c905576

+ 21 - 0
src/api/project/report-api.js

@@ -0,0 +1,21 @@
+/*
+ * @Description:
+ * @Author: admin
+ * @Date: 2021-11-05
+ * @LastEditTime: 2022-06-23
+ * @LastEditors: admin
+ */
+import { postRequest, getRequest, getDownload } from '/@/lib/axios';
+
+export const reportApi = {
+    // 分页查询 @author zhuoda
+    queryCostList: (param) => {
+        return getRequest(`/supports/delivery/day/cost/structure?date=${param}`);
+    },
+    querySummaryInfo: (param) => {
+        return getRequest(`/supports/delivery/month/cost/structure?month=${param}`);
+    },
+    querySummaryInfo: (param) => {
+        return getRequest(`/supports/delivery/month/cost/structure?month=${param}`);
+    },
+}

+ 14 - 7
src/components/common/common-table/components/table.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="common-table-item">
     <!-- 自定义顶部插槽内容 -->
-    <div v-if="tableConfig.renderTitleSlot" class="smart-table-title-slot" style="margin-bottom: 6px;background: white;">
+    <div v-if="tableConfig.renderTitleSlot" class="smart-table-title-slot" style="margin-bottom: 6px; background: white">
       <render-title-slot />
     </div>
     <!-- 查询表单 -->
@@ -63,6 +63,10 @@
 
   const props = defineProps({
     // 是否修改card样式
+    pagination: {
+      type: Boolean,
+      default: true,
+    },
     isTabs: {
       type: Boolean,
       default: false,
@@ -121,9 +125,9 @@
     renderTopSlot: {
       type: Function,
     },
-    renderTitleSlot:{
-      type:Function,
-    }
+    renderTitleSlot: {
+      type: Function,
+    },
   });
 
   // 查询表单
@@ -138,22 +142,25 @@
   // 数据总数
   const total = ref(0);
   // table默认配置
+  console.log('props.tableAttrs', props);
+
   const tableConfig = reactive({
     size: 'small',
     dataSource: [],
     columns: props.columns ? props.columns : props.tableAttrs.columns ? props.tableAttrs.columns : [],
     bordered: true,
-    pagination: true,
+    pagination: props.pagination,
     loading: false,
     scroll: props.scroll,
     ...props.tableAttrs,
     renderTopSlot: props.renderTopSlot, // 添加 renderTopSlot 属性
-    renderTitleSlot:props.renderTitleSlot,//添加renderTitleSlot属性
+    renderTitleSlot: props.renderTitleSlot, //添加renderTitleSlot属性
   });
+  console.log('tableConfig', tableConfig);
 
   const topInfo = ref({});
 
-    // 动态渲染顶部插槽内容
+  // 动态渲染顶部插槽内容
   const renderTitleSlot = () => {
     if (props.renderTitleSlot) {
       // 将 queryForm 和其他参数传递给 renderTitleSlot 函数

+ 189 - 0
src/views/project/report-manage/person-rank-month/index copy.vue

@@ -0,0 +1,189 @@
+<template>
+  <a-form class="smart-query-form">
+    <a-row class="smart-query-form-row">
+      <a-form-item label="部门名称" class="smart-query-form-item">
+        <a-input style="width: 300px" v-model:value="keywords" placeholder="请输入部门名称" />
+      </a-form-item>
+
+      <a-form-item class="smart-query-form-item smart-margin-left10">
+        <a-button-group>
+          <a-button v-privilege="'support:department:query'" type="primary" @click="onSearch">
+            <template #icon>
+              <ReloadOutlined />
+            </template>
+            查询
+          </a-button>
+          <a-button v-privilege="'support:department:query'" @click="resetQuery">
+            <template #icon>
+              <SearchOutlined />
+            </template>
+            重置
+          </a-button>
+        </a-button-group>
+        <a-button v-privilege="'system:department:add'" type="primary" @click="addDepartment" class="smart-margin-left20">
+          <template #icon>
+            <PlusOutlined />
+          </template>
+          新建
+        </a-button>
+      </a-form-item>
+    </a-row>
+  </a-form>
+
+  <a-card size="small" :bordered="true">
+    <a-table
+      size="small"
+      bordered
+      :loading="tableLoading"
+      rowKey="departmentId"
+      :columns="columns"
+      :data-source="departmentTreeData"
+      :defaultExpandAllRows="false"
+      :defaultExpandedRowKeys="defaultExpandedRowList"
+      :pagination="false"
+    >
+    </a-table>
+  </a-card>
+</template>
+
+<script setup>
+  import { onMounted, reactive, ref, watch, createVNode } from 'vue';
+  import { departmentApi } from '/src/api/system/department-api';
+  import _ from 'lodash';
+  import { smartSentry } from '/src/lib/smart-sentry';
+
+  // -----------------------  筛选 ---------------------
+  const keywords = ref('');
+
+  const columns = ref([
+    {
+      title: '提报月份',
+      dataIndex: 'submitMonth',
+    },
+    {
+      title: '姓名',
+      dataIndex: 'employeeName',
+      width: 100,
+    },
+    {
+      title: '任务类人天(小时)',
+      dataIndex: 'normalSubmitDays',
+      width: 100,
+    },
+    {
+      title: '非任务类人天(小时)',
+      dataIndex: 'unNormalSubmitDays',
+      width: 150,
+    },
+    {
+      title: '非任务类说明',
+      dataIndex: 'unNormalSubmitDaysDescribe',
+      width: 150,
+    },
+    {
+      title: '在岗时长(小时)',
+      dataIndex: 'dutyDays',
+      width: 150,
+    },
+    {
+      title: '薪资成本',
+      dataIndex: 'salaryCost',
+      width: 150,
+    },
+    {
+      title: '驻场补贴',
+      dataIndex: 'residentFixedSubsidy',
+      width: 150,
+    },
+    {
+      title: '租金',
+      dataIndex: 'rent',
+      width: 150,
+    },
+    {
+      title: '费用报销',
+      dataIndex: 'costExpense',
+      width: 150,
+    },
+    {
+      title: '杰成类预计产值',
+      dataIndex: 'jecnExpectOutput',
+      width: 150,
+    },
+    {
+      title: '奥哲类预计产值',
+      dataIndex: 'authineExpectOutput',
+      width: 150,
+    },
+    {
+      title: '船务类预计产值',
+      dataIndex: 'seaconExpectOutput',
+      width: 150,
+    },
+    {
+      title: '预计利润',
+      dataIndex: 'profitAmount',
+      width: 150,
+    },
+  ]);
+
+  onMounted(() => {
+    queryDepartmentTree();
+  });
+
+  // 查询部门列表并构建 部门树
+  async function queryDepartmentTree() {
+    try {
+      tableLoading.value = true;
+      let res = await departmentApi.queryAllDepartment();
+      let data = res.data;
+
+      data.forEach((e) => {
+        idInfoMap.value.set(e.departmentId, e);
+      });
+
+      departmentList.value = data;
+      departmentTreeData.value = buildDepartmentTree(data, DEPARTMENT_PARENT_ID);
+
+      // 默认显示 最顶级ID为列表中返回的第一条数据的ID
+      if (!_.isEmpty(departmentTreeData.value) && departmentTreeData.value.length > 0) {
+        topDepartmentId.value = departmentTreeData.value[0].departmentId;
+      }
+
+      defaultExpandedRowList.value = [];
+      defaultExpandedRowList.push(topDepartmentId.value);
+    } catch (e) {
+      smartSentry.captureError(e);
+    } finally {
+      tableLoading.value = false;
+    }
+  }
+
+  // 重置
+  function resetQuery() {
+    keywords.value = '';
+    onSearch();
+  }
+
+  // 搜索
+  function onSearch() {
+    if (!keywords.value) {
+      departmentTreeData.value = buildDepartmentTree(departmentList.value, DEPARTMENT_PARENT_ID);
+      return;
+    }
+    let originData = departmentList.value.concat();
+    if (!originData) {
+      return;
+    }
+    // 筛选出名称符合的部门
+    let filterDepartment = originData.filter((e) => e.name.indexOf(keywords.value) > -1);
+    let filterDepartmentList = [];
+    // 循环筛选出的部门 构建部门树
+    filterDepartment.forEach((e) => {
+      recursionFilterDepartment(filterDepartmentList, e.departmentId, false);
+    });
+    departmentTreeData.value = buildDepartmentTree(filterDepartmentList, DEPARTMENT_PARENT_ID);
+  }
+</script>
+
+<style scoped lang="less"></style>

+ 128 - 0
src/views/project/report-manage/person-rank-month/index.vue

@@ -0,0 +1,128 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"></CommonTable>
+</template>
+
+<script setup lang="jsx">
+  import { ref } from 'vue';
+  import useDict from '/@/utils/dict-util';
+  import { useRouter } from 'vue-router';
+
+  await useDict.init(['MATE_DELIVERY_STATUS']);
+
+  const commonTableRef = ref(null);
+  const router = useRouter();
+  const query = router.currentRoute.value.query;
+
+  const tableConfig = ref({
+    url: '/supports/delivery/employee/month/rank',
+    // 设置网络请求方式为GET
+    requestMethod: 'GET',
+    pagination: false,
+    scroll: { x: 2000, y: 600 },
+    search: [
+      {
+        label: '提报日期',
+        field: 'month',
+        type: 'dateMonth',
+      },
+    ],
+    columns: [
+      {
+        title: '提报月份',
+        dataIndex: 'submitMonth',
+        width: 100,
+        align: 'center',
+      },
+      {
+        title: '姓名',
+        dataIndex: 'employeeName',
+        width: 100,
+        align: 'center',
+      },
+      {
+        title: '任务类人天(小时)',
+        dataIndex: 'normalSubmitDays',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '非任务类人天(小时)',
+        dataIndex: 'unNormalSubmitDays',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '非任务类说明',
+        dataIndex: 'unNormalSubmitDaysDescribe',
+        width: 150,
+        ellipsis: true,
+        align: 'center',
+      },
+      {
+        title: '在岗时长(小时)',
+        dataIndex: 'dutyDays',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '薪资成本',
+        dataIndex: 'salaryCost',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '驻场补贴',
+        dataIndex: 'residentFixedSubsidy',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '租金',
+        dataIndex: 'rent',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '费用报销',
+        dataIndex: 'costExpense',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '杰成类预计产值',
+        dataIndex: 'jecnExpectOutput',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '奥哲类预计产值',
+        dataIndex: 'authineExpectOutput',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '船务类预计产值',
+        dataIndex: 'seaconExpectOutput',
+        width: 150,
+        align: 'center',
+      },
+      {
+        title: '预计利润',
+        dataIndex: 'profitAmount',
+        width: 150,
+        align: 'center',
+      },
+    ],
+    tableAttrs: {},
+    showIndexColumn: true,
+    beforeFetch({ params }) {
+      return {
+        ...params,
+        // month: query.date,
+      };
+    },
+    // afterFetch({ data }) {},
+  });
+</script>
+
+<style lang="less" scoped></style>

+ 120 - 0
src/views/project/report-manage/person-rank/index.vue

@@ -0,0 +1,120 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"></CommonTable>
+</template>
+
+<script setup lang="jsx">
+  import { ref } from 'vue';
+  import useDict from '/@/utils/dict-util';
+  import { useRouter } from 'vue-router';
+
+  await useDict.init(['MATE_DELIVERY_STATUS']);
+
+  const commonTableRef = ref(null);
+  const router = useRouter();
+  const query = router.currentRoute.value.query;
+
+  const tableConfig = ref({
+    url: '/supports/delivery/employee/rank',
+    // 设置网络请求方式为GET
+    requestMethod: 'GET',
+    pagination: false,
+    scroll: { x: 2000, y: 600 },
+    columns: [
+      {
+        title: '提报日期',
+        dataIndex: 'submitDay',
+        align: 'center',
+        width: '90px',
+      },
+      {
+        title: '姓名',
+        dataIndex: 'employeeName',
+        align: 'center',
+        width: '90px',
+      },
+      {
+        title: '任务类人天(小时)',
+        dataIndex: 'normalSubmitDays',
+        align: 'center',
+        width: '130px',
+      },
+      {
+        title: '非任务类人天(小时)',
+        dataIndex: 'unNormalSubmitDays',
+        align: 'center',
+        width: '160px',
+      },
+      {
+        title: '非任务类说明',
+        dataIndex: 'unNormalSubmitDaysDescribe',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '在岗时长(小时)',
+        dataIndex: 'dutyDays',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '薪资成本',
+        dataIndex: 'salaryCost',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '驻场补贴',
+        dataIndex: 'residentFixedSubsidy',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '租金',
+        dataIndex: 'rent',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '费用报销',
+        dataIndex: 'costExpense',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '杰成类预计产值',
+        dataIndex: 'jecnExpectOutput',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '奥哲类预计产值',
+        dataIndex: 'authineExpectOutput',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '船务类预计产值',
+        dataIndex: 'seaconExpectOutput',
+        align: 'center',
+        width: '170px',
+      },
+      {
+        title: '预计利润',
+        dataIndex: 'profitAmount',
+        align: 'center',
+        width: '170px',
+      },
+    ],
+    tableAttrs: {},
+    showIndexColumn: true,
+    beforeFetch({ params }) {
+      return {
+        ...params,
+        date: query.date,
+      };
+    },
+    // afterFetch({ data }) {},
+  });
+</script>
+
+<style lang="less" scoped></style>

+ 53 - 0
src/views/project/report-manage/report-summary/components/compositionCost.vue

@@ -0,0 +1,53 @@
+<!--
+  * 部门表单 弹窗
+  *
+  * @Author:    BoundLink
+  * @Date:      2022-08-08 20:46:18
+-->
+<template>
+  <a-modal v-model:open="visible" width="40%" title="成本构成" :footer="false" destroyOnClose>
+    <a-descriptions>
+      <a-descriptions-item label="薪资成本">¥{{ costList?.salaryCost }}</a-descriptions-item>
+      <a-descriptions-item label="驻场补贴">¥{{ costList?.residentFixedSubsidy }}</a-descriptions-item>
+      <a-descriptions-item label="办公场所租金">¥{{ costList?.rent }}</a-descriptions-item>
+      <a-descriptions-item label="费用报销">¥{{ costList?.costExpense }}</a-descriptions-item>
+      <a-descriptions-item label="杰成类预计产值">¥{{ costList?.jecnExpectOutput }}</a-descriptions-item>
+      <a-descriptions-item label="奥哲类预计产值">¥{{ costList?.authineExpectOutput }}</a-descriptions-item>
+      <a-descriptions-item label="船务类预计产值">¥{{ costList?.seaconExpectOutput }}</a-descriptions-item>
+      <a-descriptions-item label="预计利润">¥{{ costList?.profitAmount }}</a-descriptions-item>
+    </a-descriptions>
+  </a-modal>
+</template>
+<script setup>
+  import { reactive, ref, useAttrs } from 'vue';
+  import { useRouter } from 'vue-router';
+  import _ from 'lodash';
+  import { reportApi } from '/@/api/project/report-api';
+
+  // ----------------------- 对外暴漏 ---------------------
+  defineExpose({
+    showModal,
+  });
+
+  // ----------------------- modal 的显示与隐藏 ---------------------
+  const router = useRouter();
+
+  const emits = defineEmits(['refresh']);
+
+  const visible = ref(false);
+  const costList = ref(null);
+
+  function showModal(params) {
+    visible.value = true;
+    initPage(params);
+  }
+  function initPage(params) {
+    reportApi.queryCostList(params.submitDate).then((res) => {
+      costList.value = res.data;
+    });
+  }
+  function closeModal() {
+    visible.value = false;
+    resetFormData();
+  }
+</script>

+ 114 - 19
src/views/project/report-manage/report-summary/index.vue

@@ -1,28 +1,35 @@
 <template>
   <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+  <CompositionCost ref="CompositionCostRef"></CompositionCost>
 </template>
 
 <script setup lang="jsx">
-  import { ref } from 'vue';
+  import { ref, onMounted } from 'vue';
   import { useRouter } from 'vue-router';
   import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
   import useDict from '/@/utils/dict-util';
+  import CompositionCost from './components/compositionCost.vue';
+  import { reportApi } from '/@/api/project/report-api';
+
   await useDict.init(['MATE_DELIVERY_STATUS']);
 
   const commonTableRef = ref(null);
+  const CompositionCostRef = ref();
+  const summaryList = ref(null);
+  const router = useRouter();
+
   const tableConfig = ref({
     url: '/supports/delivery/day/report/summary/list',
     // 设置网络请求方式为GET
     requestMethod: 'GET',
-    scroll: { x: 'true' },
-    tableId: TABLE_ID_CONST.TEAMWORK.PROJECT_MANAGE.Task_LIST,
-    tableAttrs: {},
+    scroll: { x: 1200 },
+    // tableId: TABLE_ID_CONST.TEAMWORK.PROJECT_MANAGE.Task_LIST,
     showIndexColumn: true,
     search: [
       {
         label: '提报日期',
         field: 'submitDate',
-        type: 'date',
+        type: 'dateMonth',
       },
     ],
     columns: [
@@ -30,41 +37,42 @@
         title: '星期',
         dataIndex: 'weekCn',
         align: 'center',
-        width: '80px',
+        width: 80,
       },
       {
         title: '提报日期',
         dataIndex: 'submitDate',
         align: 'center',
-        width: '80px',
+        width: 120,
       },
       {
         title: '总工时',
         dataIndex: 'totalWorkDays',
         align: 'center',
-        width: '80px',
+        width: 80,
       },
       {
         title: '任务类工时',
         dataIndex: 'normalSubmitDays',
         align: 'center',
-        width: '90px',
+        width: 90,
       },
       {
         title: '非任务类工时',
         dataIndex: 'abnormalSubmitDays',
         align: 'center',
-        width: '90px',
+        width: 120,
       },
       {
         title: '驻场人数',
         dataIndex: 'siteCount',
         align: 'center',
-        width: '80px',
+        width: 80,
       },
       {
         title: '驻场情况',
         dataIndex: 'residentSituation',
+        align: 'center',
         width: 300,
         ellipsis: true,
       },
@@ -72,40 +80,127 @@
         title: '提报人数',
         dataIndex: 'submitCount',
         align: 'center',
-        width: '80px',
+        width: 80,
       },
       {
         title: '在岗人数',
         dataIndex: 'dutyCount',
         align: 'center',
-        width: '80px',
+        width: 80,
       },
       {
         title: '请假情况',
         dataIndex: 'leaveSituation',
         align: 'center',
-        width: '100px',
+        width: '140px',
       },
       {
         title: '需提报人数',
         dataIndex: 'requireSubmitCount',
         align: 'center',
-        width: '80px',
+        width: 110,
       },
       {
         title: '未提报人员',
         dataIndex: 'unSubmitStaff',
         align: 'center',
         width: '100px',
+        ellipsis: true,
+      },
+      {
+        title: '操作',
+        dataIndex: 'action',
+        fixed: 'right',
+        align: 'center',
+        width: 150,
+        customRender: ({ text, record, index, column }) => {
+          return (
+            <div class='smart-table-operate'>
+              <a-button type='link' onClick={() => CompositionCostRef.value.showModal(record)}>
+                成本构成
+              </a-button>
+              <a-button
+                type='link'
+                onClick={() =>
+                  router.push({
+                    path: '/project/report-manage/person-rank',
+                    query: {
+                      date: record.submitDate,
+                    },
+                  })
+                }
+              >
+                人员排名
+              </a-button>
+            </div>
+          );
+        },
       },
     ],
+    renderTopSlot() {
+      return (
+        <div style={{ display: 'flex' }}>
+          <div style={{ display: 'flex', alignItems: 'center' }}>
+            <div>
+              <span>薪资成本:</span>
+              <span style={{ fontWeight: 'bold', color: '#318586' }}>¥{summaryList.value?.salaryCost || 0}</span>
+            </div>
+            <span style={{ margin: '0 10px' }}> | </span>
+            <div>
+              <span>驻场补贴:</span>
+              <span style={{ fontWeight: 'bold', color: '#00569b' }}>¥{summaryList.value?.residentFixedSubsidy || 0}</span>
+            </div>
+            <span style={{ margin: '0 10px' }}> | </span>
+            <div>
+              <span>办公场所租金:</span>
+              <span style={{ fontWeight: 'bold', color: '#00569b' }}>¥{summaryList.value?.rent || 0}</span>
+            </div>
+            <span style={{ margin: '0 10px' }}> | </span>
+            <div>
+              <span>费用报销:</span>
+              <span style={{ fontWeight: 'bold', color: '#ffad2a' }}>¥{summaryList.value?.costExpense || 0}</span>
+            </div>
+            <span style={{ margin: '0 10px' }}> | </span>
+            <div>
+              <span>杰成类预计产值:</span>
+              <span style={{ fontWeight: 'bold', color: '#2B69F8' }}>¥{summaryList.value?.jecnExpectOutput}</span>
+            </div>
+            <span style={{ margin: '0 10px' }}> | </span>
+            <div>
+              <span>奥哲类预计产值:</span>
+              <span style={{ fontWeight: 'bold', color: '#2B69F8' }}>¥{summaryList.value?.authineExpectOutput}</span>
+            </div>
+            <span style={{ margin: '0 10px' }}> | </span>
+            <div>
+              <span>船务类预计产值:</span>
+              <span style={{ fontWeight: 'bold', color: '#2B69F8' }}>¥{summaryList.value?.seaconExpectOutput}</span>
+            </div>
+            <span style={{ margin: '0 10px' }}> | </span>
+            <div>
+              <span>预计利润:</span>
+              <span style={{ fontWeight: 'bold', color: '#69b259' }}>¥{summaryList.value?.profitAmount}</span>
+            </div>
+          </div>
+        </div>
+      );
+    },
     beforeFetch({ params }) {
+      querySummaryInfo(params.submitDate);
       return {
         ...params,
       };
     },
-    // afterFetch({ data }) {},
+    // afterFetch(data) {},
   });
+  onMounted(() => {
+    querySummaryInfo();
+  });
+  function querySummaryInfo(data = '') {
+    reportApi.querySummaryInfo(data).then((res) => {
+      summaryList.value = res.data;
+      console.log('summaryList', summaryList);
+    });
+  }
 </script>
 
 <style lang="less" scoped>
@@ -117,7 +212,7 @@
     height: 27px !important;
     font-size: 11px !important;
   }
-  :deep(.ant-table-column[data-key='index']) {
-    width: 60px !important;
-  }
+  // :deep(.ant-table-column[data-key='index']) {
+  //   width: 60px !important;
+  // }
 </style>