Bläddra i källkod

增加资产折旧-基本信息

liuyanpeng 1 år sedan
förälder
incheckning
f4c502e2b0

+ 196 - 0
src/api/assetPeriodDepreciate/index.js

@@ -0,0 +1,196 @@
+
+import Common from '../../common/Common.js';
+
+// 获取所有资产分类大类(包含子类)
+export const queryCategoriesApi = () => {
+  const requestUrl = 'AssetCategoryResource/queryRootAssetCategories';
+
+  return new Promise((resolve, reject) => {
+    $.ajax({
+      url: Common.getApiURL(requestUrl),
+      type: 'get',
+      dataType: 'json',
+
+      beforeSend: function (request) {
+        Common.addTokenToRequest(request);
+      },
+      success: function (data) {
+        resolve(data);
+      },
+      error: function (XMLHttpRequest, textStatus, errorThrown) {
+        reject(XMLHttpRequest);
+      },
+    });
+  });
+};
+
+// 根据资产分类名称分页查询资产分类信息(默认查询全部)
+export const queryByNameApi = params => {
+  const requestUrl = 'AssetCategoryResource/listAssetCategoryByName';
+
+  return new Promise((resolve, reject) => {
+    $.ajax({
+      url: Common.getApiURL(requestUrl),
+      type: 'post',
+      contentType: 'application/json',
+      dataType: 'json',
+      data: JSON.stringify(params),
+
+      beforeSend: function (request) {
+        Common.addTokenToRequest(request);
+      },
+      success: function (data) {
+        resolve(data);
+      },
+      error: function (XMLHttpRequest, textStatus, errorThrown) {
+        reject(XMLHttpRequest);
+      },
+    });
+  });
+};
+
+// 根据资产分类id查询资产分类信息
+export const queryByIdApi = id => {
+  const requestUrl = `AssetCategoryResource/getAssetCategorysByAssetCategoryId?assetCategoryId=${id}`;
+
+  return new Promise((resolve, reject) => {
+    $.ajax({
+      url: Common.getApiURL(requestUrl),
+      type: 'get',
+      dataType: 'json',
+
+      beforeSend: function (request) {
+        Common.addTokenToRequest(request);
+      },
+      success: function (data) {
+        resolve(data);
+      },
+      error: function (XMLHttpRequest, textStatus, errorThrown) {
+        reject(XMLHttpRequest);
+      },
+    });
+  });
+};
+
+// 查询所有资产折旧方法
+export const getMethodsApi = () => {
+  const requestUrl = 'depreciationMethodResource/getDepreciationMethods';
+
+  return new Promise((resolve, reject) => {
+    $.ajax({
+      url: Common.getApiURL(requestUrl),
+      type: 'get',
+      dataType: 'json',
+
+      beforeSend: function (request) {
+        Common.addTokenToRequest(request);
+      },
+      success: function (data) {
+        resolve(data);
+      },
+      error: function (XMLHttpRequest, textStatus, errorThrown) {
+        reject(XMLHttpRequest);
+      },
+    });
+  });
+};
+
+// 设置折旧方法
+export const updateMethodApi = params => {
+  const requestUrl = 'AssetCategoryResource/updateAssetCategoryDepreciationMethod';
+
+  return new Promise((resolve, reject) => {
+    $.ajax({
+      url: Common.getApiURL(requestUrl),
+      type: 'post',
+      contentType: 'application/json',
+      dataType: 'json',
+      data: JSON.stringify(params),
+
+      beforeSend: function (request) {
+        Common.addTokenToRequest(request);
+      },
+      success: function (data) {
+        resolve(data);
+      },
+      error: function (XMLHttpRequest, textStatus, errorThrown) {
+        reject(XMLHttpRequest);
+      },
+    });
+  });
+};
+
+// 设置折旧年限
+export const updateYearApi = params => {
+  const requestUrl = 'AssetCategoryResource/updateAssetCategoryUsedYearLimit';
+
+  return new Promise((resolve, reject) => {
+    $.ajax({
+      url: Common.getApiURL(requestUrl),
+      type: 'post',
+      contentType: 'application/json',
+      dataType: 'json',
+      data: JSON.stringify(params),
+
+      beforeSend: function (request) {
+        Common.addTokenToRequest(request);
+      },
+      success: function (data) {
+        resolve(data);
+      },
+      error: function (XMLHttpRequest, textStatus, errorThrown) {
+        reject(XMLHttpRequest);
+      },
+    });
+  });
+};
+
+// 设置计提折旧或不提折旧
+export const updateExtractApi = params => {
+  const requestUrl = 'AssetCategoryResource/updateAssetCategoryExtractDepreciation';
+
+  return new Promise((resolve, reject) => {
+    $.ajax({
+      url: Common.getApiURL(requestUrl),
+      type: 'post',
+      contentType: 'application/json',
+      dataType: 'json',
+      data: JSON.stringify(params),
+
+      beforeSend: function (request) {
+        Common.addTokenToRequest(request);
+      },
+      success: function (data) {
+        resolve(data);
+      },
+      error: function (XMLHttpRequest, textStatus, errorThrown) {
+        reject(XMLHttpRequest);
+      },
+    });
+  });
+};
+
+// 设置残值率 
+export const updateReservedRateApi = params => {
+  const requestUrl = 'AssetCategoryResource/updateAssetCategoryReservedRate';
+
+  return new Promise((resolve, reject) => {
+    $.ajax({
+      url: Common.getApiURL(requestUrl),
+      type: 'post',
+      contentType: 'application/json',
+      dataType: 'json',
+      data: JSON.stringify(params),
+
+      beforeSend: function (request) {
+        Common.addTokenToRequest(request);
+      },
+      success: function (data) {
+        resolve(data);
+      },
+      error: function (XMLHttpRequest, textStatus, errorThrown) {
+        reject(XMLHttpRequest);
+      },
+    });
+  });
+};

+ 6 - 0
src/common/CommonTable.vue

@@ -84,6 +84,11 @@ const props = defineProps({
     type: Boolean,
     default: true,
   },
+  // 分页在右上角
+  topRight: {
+    type: Boolean,
+    default: false,
+  },
   // 表格距底部高度
   extraHeight: {
     type: Number,
@@ -110,6 +115,7 @@ const pagination = reactive({
   onShowSizeChange: (current, pageSize) => showSizeChange(current, pageSize),
   onChange: (current, pageSize) => changePage(current, pageSize), //点击页码事件
   total: props.total,
+  position:props.topRight ? ['topRight'] : ['bottomRight'],
 });
 
 const yScroll = ref(400); //默认滚动高度

+ 120 - 0
src/components/assetPeriodDepreciate/DepreciationIndex.vue

@@ -0,0 +1,120 @@
+<template>
+  <div class="container_menu">
+    <ul class="nav nav-tabs m-row">
+      <li
+        v-for="(item, index) in menus" :key="index" role="presentation"
+        :class="{ active: currentTabIndex === index }" @click="menuChanged(index, item.infoWindowNo)"
+      >
+        <a>{{ item.menuName }}</a>
+        <span
+          :class="{
+            jt: true,
+            active: currentTabIndex === index,
+          }"
+        />
+      </li>
+    </ul>
+  </div>
+  <div class="container_content">
+    <DepreciationInformation v-if="currentTabIndex === 0" />
+  </div>
+  <!-- <InfoWindow
+    v-if="infoWindowNo"
+    ref="info"
+    :info-window-no="infoWindowNo"
+    :is-search-widget="false"
+  /> -->
+</template>
+
+<script setup>
+import { useRouter } from 'vue-router';
+import { ref, onMounted } from 'vue';
+import DepreciationInformation from './DepreciationInformation.vue';
+
+const menus = [
+  {
+    menuName: '基本信息',
+    infoWindowNo: null,
+  },
+  {
+    menuName: '设置年限',
+    infoWindowNo: '20240922_095937',
+  },
+  {
+    menuName: '提取折旧',
+    infoWindowNo: '20241014_105157',
+  },
+  {
+    menuName: '查询统计',
+    infoWindowNo: '20240922_095937',
+  },
+];
+
+const router = useRouter();
+
+const infoWindowNo = ref(null);
+const currentTabIndex = ref(0);
+
+// onMounted(() => {
+//   const { menuIndex, windowNo } = JSON.parse(
+//     localStorage.getItem('shortcutMenu'),
+//   );
+//   menuChanged(menuIndex, windowNo);
+// });
+
+const menuChanged = (index, windowNo) => {
+  currentTabIndex.value = index;
+  if (windowNo) {
+    infoWindowNo.value = windowNo;
+  } else {
+    router.push('/desktop/dashboard');
+  }
+};
+</script>
+
+<style scoped>
+:deep(.flex-container-modal) {
+    height: calc(100vh - 100px) !important;
+}
+
+.nav-tabs>li {
+    width: 74px;
+    cursor: pointer;
+}
+
+.m-row {
+    margin-bottom: 0;
+}
+
+.nav>li>a {
+    padding: 6px 4px;
+    text-align: center;
+}
+
+.nav-tabs>li>a {
+    color: black;
+}
+
+.nav-tabs>li.active>a {
+    color: #fff;
+    border: 1px solid #ddd;
+    background-color: #2681cf;
+    border-radius: 4px;
+    border-bottom: none;
+}
+
+.jt {
+    position: absolute;
+    top: 33px;
+    left: 27px;
+    border: 8px solid transparent;
+}
+
+.jt.active {
+    border-top-color: #277fd0;
+}
+
+.container_content {
+    padding-top: 8px;
+}
+</style>

+ 434 - 0
src/components/assetPeriodDepreciate/DepreciationInformation.vue

@@ -0,0 +1,434 @@
+<template>
+  <div>
+    <a-row>
+      <a-col flex="15%" class="tree_box">
+        <a-tree
+          v-model:expandedKeys="expandedKeys" v-model:selectedKeys="selectedKeys"
+          :field-names="{ title: 'text', key: 'id' }" :tree-data="treeDatas" :show-line="true"
+          @select="categoriesSelected"
+        />
+      </a-col>
+      <a-col flex="auto" class="table_box" style="width: 0;">
+        <div class="operation_box">
+          <a-input-search
+            v-model:value="searchParams.name" size="small"
+            style="width: 300px;margin:0 0 8px 0;" enter-button @search="searchChange"
+          />
+          <a-pagination
+            v-model:current="current" simple size="small" :total="infoTotal"
+            :default-page-size="20" @change="getPageParams"
+          />
+        </div>
+
+        <div class="operation_box">
+          <a-space>
+            <a-button size="small" :icon="h(FieldTimeOutlined)" @click="operation('设置折旧年限')">
+              设置折旧年限
+            </a-button>
+            <a-button size="small" :icon="h(MoneyCollectOutlined)" @click="setDepreciation">
+              设置计提折旧
+            </a-button>
+            <a-button size="small" :icon="h(PayCircleOutlined)" @click="cancelDepreciation">
+              设置不提折旧
+            </a-button>
+            <a-button size="small" :icon="h(ProfileOutlined)" @click="operation('设置折旧方法')">
+              设置折旧方法
+            </a-button>
+            <a-button size="small" :icon="h(PercentageOutlined)" @click="operation('设置残值率')">
+              设置残值率
+            </a-button>
+          </a-space>
+          <a-space>
+            <!-- <a-button size="small" :icon="h(DownloadOutlined)">导出</a-button> -->
+          </a-space>
+        </div>
+        <CommonTable
+          ref="commonTable" :is-select="true" :selected-keys="selectedIds" :have-page="false"
+          :columns="columns" :data-source="dataSource" :top-right="true" :is-loading="isLoading"
+          @get-selected="getSelectColumn"
+        >
+          <template #bodyCell="{ column, record }">
+            <template v-if="column.dataIndex === 'reservedRate'">
+              <span v-if="record.reservedRate">{{ record.reservedRate }}%</span>
+              <span v-else />
+            </template>
+          </template>
+        </CommonTable>
+      </a-col>
+    </a-row>
+    <div class="footer_box">
+      <p>您所选的资产共计:<span style="color: red;">{{ selectedIds.length }}</span> 条</p>
+    </div>
+  </div>
+  <a-modal v-model:open="visible" width="26%" :title="modalTitle" @ok="setDepreciationInfo">
+    <a-form-item v-if="modalTitle === '设置折旧年限'" label="请输入" style="margin-top: 24px;">
+      <a-input-number v-model:value="yearLimit" :controls="false" addon-after="月" style="width: 90%;" />
+    </a-form-item>
+    <a-form-item v-if="modalTitle === '设置折旧方法'" label="请选择" style="margin-top: 24px;">
+      <a-select
+        v-model:value="depreciationMethod" style="width: 90%" :options="depreciationMethods"
+        :field-names="{ label: 'text', value: 'id' }"
+      />
+    </a-form-item>
+    <a-form-item v-if="modalTitle === '设置残值率'" label="请输入" style="margin-top: 24px;">
+      <a-input-number
+        v-model:value="reservedRate" :controls="false" :step="0.01" :min="0" :max="100"
+        :formatter="value => `${value}%`" :parser="value => value.replace('%', '')" style="width: 90%;"
+      />
+    </a-form-item>
+  </a-modal>
+</template>
+
+<script setup>
+import { ref, reactive, h } from 'vue';
+import Common from '../../common/Common';
+import CommonTable from '../../common/CommonTable.vue';
+import { FieldTimeOutlined, MoneyCollectOutlined, PayCircleOutlined, DownloadOutlined, ProfileOutlined, PercentageOutlined } from '@ant-design/icons-vue';
+import {
+  queryCategoriesApi, queryByNameApi, queryByIdApi, updateYearApi, updateExtractApi, getMethodsApi, updateMethodApi,
+  updateReservedRateApi,
+} from '../../api/assetPeriodDepreciate';
+import { infoColumns, debounce } from './util.js';
+import { message, Modal } from 'ant-design-vue';
+
+// 表格配置
+const commonTable = ref();
+const infoTotal = ref(0);
+const dataSource = ref([]);
+const columns = ref(infoColumns);
+const selectedIds = ref([]); // 用作表格选择的唯一key值
+const current = ref(1);
+// 树形配置
+const expandedKeys = ref([]);
+const selectedKeys = ref([]);
+const treeDatas = ref([]);
+// 折旧方法
+const depreciationMethod = ref('');
+const depreciationMethods = ref([]);
+
+const visible = ref(false);
+const modalTitle = ref('');
+const yearLimit = ref(null); // 折旧年限
+const reservedRate = ref(null); // 残值率
+const isLoading = ref(false);
+const isAllSearch = ref(true);
+const selectCategory = ref(null);
+const selectCategoryId = ref([]);
+
+// 查询参数
+const searchParams = reactive({
+  name: '',
+  range: {
+    start: 0,
+    length: 20,
+  },
+});
+
+const clearDatas = () => {
+  modalTitle.value = '';
+  yearLimit.value = null;
+  reservedRate.value = null;
+  depreciationMethod.value = null;
+  visible.value = false;
+  selectedIds.value = [];
+  commonTable.value.clear();
+};
+
+// 打开模态框
+const operation = title => {
+  if (!selectedIds.value || selectedIds.value.length === 0) {
+    message.warning('请您至少选择一条分类数据。');
+    return;
+  }
+  modalTitle.value = title;
+  visible.value = true;
+};
+
+// 设置折旧年限/折旧方法/残值率
+const setDepreciationInfo = () => {
+  if (modalTitle.value === '设置折旧年限') {
+    const params = {
+      usedYearLimit: yearLimit.value,
+      assetCategoryIds: selectedIds.value,
+    };
+    setYearLimit(params);
+  } else if (modalTitle.value === '设置折旧方法') {
+    const params = {
+      depreciationMethodId: depreciationMethod.value,
+      assetCategoryIds: selectedIds.value,
+    };
+    setMethod(params);
+  } else {
+    const params = {
+      reservedRate: reservedRate.value,
+      assetCategoryIds: selectedIds.value,
+    };
+    setReservedRate(params);
+  }
+};
+
+// 设置折旧年限
+const setYearLimit = params => {
+  updateYearApi(params).then(
+    success => {
+      if (success.errorCode === 0) {
+        message.success('设置折旧年限成功。');
+      } else {
+        message.warning(success.errorMessage);
+      }
+      clearDatas();
+      if (isAllSearch.value) {
+        searchChange();
+      } else {
+        categoriesSelected();
+      }
+    },
+    error => {
+      Common.processException(error);
+    },
+  );
+};
+
+// 设置折旧方法
+const setMethod = params => {
+  updateMethodApi(params).then(
+    success => {
+      if (success.errorCode === 0) {
+        message.success('设置折旧方法成功。');
+      } else {
+        message.warning(success.errorMessage);
+      }
+      clearDatas();
+      if (isAllSearch.value) {
+        searchChange();
+      } else {
+        categoriesSelected();
+      }
+    },
+    error => {
+      Common.processException(error);
+    },
+  );
+};
+
+// 设置残值率
+const setReservedRate = params => {
+  updateReservedRateApi(params).then(
+    success => {
+      if (success.errorCode === 0) {
+        message.success('设置残值率成功。');
+      } else {
+        message.warning(success.errorMessage);
+      }
+      clearDatas();
+      if (isAllSearch.value) {
+        searchChange();
+      } else {
+        categoriesSelected();
+      }
+    },
+    error => {
+      Common.processException(error);
+    },
+  );
+};
+
+// 设置计提折旧
+const setDepreciation = () => {
+  if (!selectedIds.value || selectedIds.value.length === 0) {
+    message.warning('请您至少选择一条分类数据。');
+    return;
+  }
+  Modal.confirm({
+    title: '提示',
+    content: h('div', {}, '您确定要将所选数据设置为计提折旧吗?'),
+    onOk() {
+      updateExtractDepreciation(true);
+    },
+  });
+};
+// 设置不提折旧
+const cancelDepreciation = () => {
+  if (!selectedIds.value || selectedIds.value.length === 0) {
+    message.warning('请您至少选择一条分类数据。');
+    return;
+  }
+  Modal.confirm({
+    title: '提示',
+    content: h('div', {}, '您确定要将所选数据设置为不提折旧吗?'),
+    onOk() {
+      updateExtractDepreciation(false);
+    },
+  });
+};
+
+// 根据分类ID查询折旧信息(处理刷新情况,避免点击父类资产时刷新无效)
+const categoriesSelected = (key, selected) => {
+  let nowKey;
+  let nowCategory;
+  if (selected) {
+    if (!selected.node.dataRef.children) {
+      selectCategoryId.value = nowKey = key;
+      selectCategory.value = nowCategory = selected;
+    }
+  } else {
+    nowKey = [...selectCategoryId.value];
+    nowCategory = { ...selectCategory.value };
+  }
+  if (nowKey && nowKey.length) {
+    if (!nowCategory.node.dataRef.children) {
+      queryByIdApi(nowKey[0]).then(
+        success => {
+          if (success.name) {
+            dataSource.value = [{ ...success }];
+          }
+          isAllSearch.value = false;
+        },
+        error => {
+          Common.processException(error);
+        },
+      );
+    }
+  }
+
+};
+
+// 获取的分页参数并查询
+const getPageParams = (start, length) => {
+  current.value = start;
+  searchParams.range.start = (start - 1) * length;
+  searchParams.range.length = length;
+  getInfo();
+};
+
+// 查询回到第一页
+const searchChange = debounce(() => {
+  getPageParams(1, 20);
+}, 500);
+
+// 获取所选项的数据
+const getSelectColumn = rows => {
+  selectedIds.value = rows.selectedRowKeys;
+};
+
+// 获取资产分类
+const getCategories = () => {
+  queryCategoriesApi().then(
+    success => {
+      if (success && success.length) {
+        treeDatas.value = success;
+      }
+    },
+    error => {
+      Common.processException(error);
+
+    },
+  );
+};
+
+// 根据分类名字查询信息
+const getInfo = () => {
+  isLoading.value = true;
+  const params = JSON.parse(JSON.stringify(searchParams));
+  queryByNameApi(params).then(
+    success => {
+      if (success.dataList && success.dataList.length) {
+        dataSource.value = success.dataList;
+      }
+      infoTotal.value = success.totalSize;
+      isLoading.value = false;
+      isAllSearch.value = true;
+    },
+    error => {
+      isLoading.value = false;
+      Common.processException(error);
+    },
+  );
+};
+
+// 查询所有资产折旧方法
+const getMethods = () => {
+  getMethodsApi().then(
+    success => {
+      if (success.errorCode === 0) {
+        if (success.datas && success.datas.length) {
+          depreciationMethods.value = success.datas;
+        }
+      } else {
+        message.warning(success.errorMessage);
+      }
+    },
+    error => {
+      Common.processException(error);
+    },
+  );
+};
+// 设置计提折旧或不提折旧
+const updateExtractDepreciation = flag => {
+  const params = {
+    isExtractDepreciation: flag,
+    assetCategoryIds: selectedIds.value,
+  };
+  updateExtractApi(params).then(
+    success => {
+      if (success.errorCode === 0) {
+        if (flag) {
+          message.success('设置计提折旧成功。');
+        } else {
+          message.success('设置不提折旧成功。');
+        }
+        clearDatas();
+        if (isAllSearch.value) {
+          searchChange();
+        } else {
+          categoriesSelected();
+        }
+      } else {
+        message.warning(success.errorMessage);
+      }
+    },
+    error => {
+      Common.processException(error);
+    },
+  );
+};
+
+getInfo();
+getMethods();
+getCategories();
+
+</script>
+
+<style scoped>
+.tree_box {
+    height: 86vh;
+    overflow: auto;
+    border: 1px solid #dddddd;
+    margin-right: 4px;
+    border-bottom: none;
+}
+
+.table_box {
+    padding: 6px;
+    border: 1px solid #dddddd;
+    border-bottom: none;
+}
+
+.operation_box {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.ant-btn>span {
+    color: #267fcf;
+}
+
+.footer_box {
+    background-color: #fafafa;
+}
+p{
+    margin: 0 !important;
+    padding: 0 !important;
+}
+</style>

+ 53 - 0
src/components/assetPeriodDepreciate/util.js

@@ -0,0 +1,53 @@
+
+
+export const infoColumns = [
+  {
+    title: '资产分类名称',
+    key: 'name',
+    dataIndex: 'name',
+    width: 150,
+  },
+  {
+    title: '折旧方法',
+    key: 'depreciationMethodName',
+    dataIndex: 'depreciationMethodName',
+    width: 100,
+  },
+  {
+    title: '折旧年限(月)',
+    key: 'usedYearLimit',
+    dataIndex: 'usedYearLimit',
+    width: 100,
+  },
+  {
+    title: '是否折旧',
+    key: 'isExtractDepreciation',
+    dataIndex: 'isExtractDepreciation',
+    width: 100,
+    customCell: record => {
+      if (record.isExtractDepreciation === true) {
+        record.isExtractDepreciation = '是';
+      } else if (record.isExtractDepreciation === false) {
+        record.isExtractDepreciation = '否';
+      }
+    },
+  },
+  {
+    title: '残值率',
+    key: 'reservedRate',
+    dataIndex: 'reservedRate',
+    width: 100,
+  },
+].map(item => ({ ...item, align: 'center', resizable: true, maxWidth: 200, minWidth: 75 }));
+
+
+// 防抖函数
+export const debounce = (fn, wait = 1000) => {
+  let timer;
+  return function (...args) {
+    clearTimeout(timer);
+    timer = setTimeout(() => {
+      fn.call(this, args);
+    }, wait);
+  };
+};

+ 2 - 0
src/index.js

@@ -45,6 +45,7 @@ import RunDataArchive from './components/customer/RunDataArchive.vue';
 import AssetRfidRecord from './components/rfidRecord/AssetRfidRecord.vue';
 import BatchUploadImages from './components/sonicAlbumUpload/index.vue';
 import AssetInstanceFullCalendar from './customer/AssetInstanceFullCalendar.vue';
+import DepreciationIndex from './components/assetPeriodDepreciate/DepreciationIndex.vue';
 
 export {
   langZhCn,
@@ -91,4 +92,5 @@ export {
   BatchUploadImages,
   AssetLabelPrinting,
   AssetInstanceFullCalendar,
+  DepreciationIndex,
 };

+ 5 - 0
src/router/index.js

@@ -41,6 +41,8 @@ const AssetInstanceFullCalendar = () => import('../customer/AssetInstanceFullCal
 
 const InventoryGlobalView = () => import('../components/inventory1/InventoryGlobalView.vue');
 
+const DepreciationIndex = () => import('../components/assetPeriodDepreciate/DepreciationIndex.vue')
+
 const routes = [
 
   { path: '/eam/hello-world', component: HelloWorld },
@@ -316,6 +318,9 @@ const routes = [
   { 
     path: '/eam/InventoryGlobalView', component: InventoryGlobalView, 
   },
+  { 
+    path: '/eam/assetPeriodDepreciate', component: DepreciationIndex,  // 资产折旧
+  },
 ];