From 41de91c90854bc2794d4fe5383aa5fb64f464028 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 16 六月 2026 11:27:32 +0800
Subject: [PATCH] pro 1.平遥县盛达铸造厂部署修改

---
 src/views/financialManagement/assets/fixedAssets.vue |  495 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 495 insertions(+), 0 deletions(-)

diff --git a/src/views/financialManagement/assets/fixedAssets.vue b/src/views/financialManagement/assets/fixedAssets.vue
new file mode 100644
index 0000000..95eb017
--- /dev/null
+++ b/src/views/financialManagement/assets/fixedAssets.vue
@@ -0,0 +1,495 @@
+<template>
+  <div class="app-container">
+    <el-form :model="filters" :inline="true">
+      <el-form-item label="璧勪骇缂栧彿:">
+        <el-input v-model="filters.assetCode" placeholder="璇疯緭鍏ヨ祫浜х紪鍙�" clearable style="width: 200px;" />
+      </el-form-item>
+      <el-form-item label="璧勪骇鍚嶇О:">
+        <el-input v-model="filters.assetName" placeholder="璇疯緭鍏ヨ祫浜у悕绉�" clearable style="width: 200px;" />
+      </el-form-item>
+      <el-form-item label="璧勪骇绫诲埆:">
+        <el-select v-model="filters.category" placeholder="璇烽�夋嫨绫诲埆" clearable style="width: 150px;">
+          <el-option label="鎴垮眿寤虹瓚" value="building" />
+          <el-option label="鏈哄櫒璁惧" value="machine" />
+          <el-option label="杩愯緭宸ュ叿" value="vehicle" />
+          <el-option label="鐢靛瓙璁惧" value="electronic" />
+          <el-option label="鍔炲叕瀹跺叿" value="furniture" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鐘舵��:">
+        <el-select v-model="filters.status" placeholder="璇烽�夋嫨鐘舵��" clearable style="width: 150px;">
+          <el-option label="鍦ㄧ敤" value="in_use" />
+          <el-option label="闂茬疆" value="idle" />
+          <el-option label="鎶ュ簾" value="scrapped" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+        <el-button @click="resetFilters">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+    <div class="table_list">
+      <div class="actions">
+        <div>
+          <el-statistic title="璧勪骇鍘熷�煎悎璁�" :value="totalOriginalValue" precision="2" prefix="楼" />
+          <el-statistic title="绱鎶樻棫鍚堣" :value="totalDepreciation" precision="2" prefix="楼" style="margin-left: 30px;" />
+          <el-statistic title="鍑�鍊煎悎璁�" :value="totalNetValue" precision="2" prefix="楼" style="margin-left: 30px;" />
+        </div>
+        <div>
+          <el-button type="primary" @click="add" icon="Plus">鏂板璧勪骇</el-button>
+          <el-button type="warning" @click="handleDepreciation" icon="Money">鎶樻棫璁℃彁</el-button>
+          <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
+        </div>
+      </div>
+      <PIMTable
+        rowKey="id"
+        isSelection
+        :column="columns"
+        :tableData="dataList"
+        :page="{
+          current: pagination.currentPage,
+          size: pagination.pageSize,
+          total: pagination.total,
+        }"
+        @selection-change="handleSelectionChange"
+        @pagination="changePage"
+      >
+        <template #originalValue="{ row }">
+          <span class="text-primary">楼{{ formatMoney(row.originalValue) }}</span>
+        </template>
+        <template #accumulatedDepreciation="{ row }">
+          <span class="text-warning">楼{{ formatMoney(row.accumulatedDepreciation) }}</span>
+        </template>
+        <template #netValue="{ row }">
+          <span class="text-success">楼{{ formatMoney(row.netValue) }}</span>
+        </template>
+        <template #category="{ row }">
+          <el-tag>{{ getCategoryLabel(row.category) }}</el-tag>
+        </template>
+        <template #status="{ row }">
+          <el-tag :type="getStatusType(row.status)">{{ getStatusLabel(row.status) }}</el-tag>
+        </template>
+        <template #operation="{ row }">
+          <el-button type="primary" link @click="view(row)">鏌ョ湅</el-button>
+          <el-button type="primary" link @click="edit(row)">缂栬緫</el-button>
+          <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
+        </template>
+      </PIMTable>
+    </div>
+
+    <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
+      <el-form :model="form" :rules="rules" :disabled="isView" ref="formRef" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="璧勪骇缂栧彿" prop="assetCode">
+              <el-input v-model="form.assetCode" placeholder="淇濆瓨鍚庤嚜鍔ㄧ敓鎴�" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璧勪骇鍚嶇О" prop="assetName">
+              <el-input v-model="form.assetName" placeholder="璇疯緭鍏ヨ祫浜у悕绉�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="璧勪骇绫诲埆" prop="category">
+              <el-select v-model="form.category" placeholder="璇烽�夋嫨璧勪骇绫诲埆" style="width: 100%;">
+                <el-option label="鎴垮眿寤虹瓚" value="building" />
+                <el-option label="鏈哄櫒璁惧" value="machine" />
+                <el-option label="杩愯緭宸ュ叿" value="vehicle" />
+                <el-option label="鐢靛瓙璁惧" value="electronic" />
+                <el-option label="鍔炲叕瀹跺叿" value="furniture" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瑙勬牸鍨嬪彿" prop="specification">
+              <el-input v-model="form.specification" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="璐疆鏃ユ湡" prop="purchaseDate">
+              <el-date-picker v-model="form.purchaseDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璧勪骇鍘熷��" prop="originalValue">
+              <el-input-number v-model="form.originalValue" :min="0" :precision="2" style="width: 100%;" @change="calculateNetValue" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浣跨敤骞撮檺" prop="usefulLife">
+              <el-input-number v-model="form.usefulLife" :min="1" :max="50" style="width: 100%;" />
+              <span style="margin-left: 10px;">骞�</span>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="娈嬪�肩巼" prop="residualRate">
+              <el-input-number v-model="form.residualRate" :min="0" :max="10" :precision="2" style="width: 100%;" />
+              <span style="margin-left: 10px;">%</span>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="绱鎶樻棫">
+              <el-input v-model="form.accumulatedDepreciation" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璧勪骇鍑�鍊�">
+              <el-input v-model="form.netValue" disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="瀛樻斁鍦扮偣" prop="location">
+              <el-input v-model="form.location" placeholder="璇疯緭鍏ュ瓨鏀惧湴鐐�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浣跨敤閮ㄩ棬" prop="department">
+              <el-input v-model="form.department" placeholder="璇疯緭鍏ヤ娇鐢ㄩ儴闂�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="淇濈浜�" prop="keeper">
+              <el-input v-model="form.keeper" placeholder="璇疯緭鍏ヤ繚绠′汉" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐘舵��" prop="status">
+              <el-select v-model="form.status" placeholder="璇烽�夋嫨鐘舵��" style="width: 100%;">
+                <el-option label="鍦ㄧ敤" value="in_use" />
+                <el-option label="闂茬疆" value="idle" />
+                <el-option label="鎶ュ簾" value="scrapped" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍒涘缓鏃堕棿" prop="createTime">
+              <el-date-picker v-model="createTimeDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%;" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button v-if="!isView" type="primary" @click="submitForm">纭畾</el-button>
+        <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+      </template>
+    </FormDialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, computed } from "vue";
+import dayjs from "dayjs";
+import { ElMessage, ElMessageBox } from "element-plus";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import {
+  listFixedAssetPage,
+  addFixedAsset,
+  updateFixedAsset,
+  deleteFixedAsset,
+  depreciateFixedAsset,
+} from "@/api/financialManagement/fixedAsset";
+
+defineOptions({
+  name: "鍥哄畾璧勪骇",
+});
+
+const filters = reactive({
+  assetCode: "",
+  assetName: "",
+  category: "",
+  status: "",
+});
+
+const pagination = reactive({
+  currentPage: 1,
+  pageSize: 10,
+  total: 0,
+});
+
+const columns = [
+  { label: "璧勪骇缂栧彿", prop: "assetCode", width: "130" },
+  { label: "璧勪骇鍚嶇О", prop: "assetName", width: "150" },
+  { label: "璧勪骇绫诲埆", prop: "category", dataType: "slot", slot: "category" },
+  { label: "瑙勬牸鍨嬪彿", prop: "specification", width: "120" },
+  { label: "璧勪骇鍘熷��", prop: "originalValue", dataType: "slot", slot: "originalValue" },
+  { label: "绱鎶樻棫", prop: "accumulatedDepreciation", dataType: "slot", slot: "accumulatedDepreciation" },
+  { label: "璧勪骇鍑�鍊�", prop: "netValue", dataType: "slot", slot: "netValue" },
+  { label: "鐘舵��", prop: "status", dataType: "slot", slot: "status" },
+  { label: "鎿嶄綔", prop: "operation", dataType: "slot", slot: "operation", width: "180", fixed: "right" },
+];
+
+const dataList = ref([]);
+const multipleList = ref([]);
+const dialogVisible = ref(false);
+const dialogTitle = ref("");
+const formRef = ref(null);
+const isEdit = ref(false);
+const isView = ref(false);
+const currentId = ref(null);
+const selectedIds = computed(() =>
+  multipleList.value
+    .map(item => item?.id)
+    .filter(id => id !== undefined && id !== null && id !== "")
+);
+
+const createDefaultForm = () => ({
+  assetCode: "",
+  assetName: "",
+  category: "",
+  specification: "",
+  purchaseDate: "",
+  originalValue: 0,
+  usefulLife: 5,
+  residualRate: 5,
+  accumulatedDepreciation: 0,
+  netValue: 0,
+  location: "",
+  department: "",
+  keeper: "",
+  status: "in_use",
+  remark: "",
+  createTime: "",
+});
+
+const form = reactive({
+  ...createDefaultForm(),
+});
+const createTimeDate = computed({
+  get: () => (form.createTime ? String(form.createTime).split(" ")[0] : ""),
+  set: (value) => {
+    form.createTime = value ? `${value} ${dayjs().format("HH:mm:ss")}` : "";
+  },
+});
+
+const rules = {
+  assetName: [{ required: true, message: "璇疯緭鍏ヨ祫浜у悕绉�", trigger: "blur" }],
+  category: [{ required: true, message: "璇烽�夋嫨璧勪骇绫诲埆", trigger: "change" }],
+  purchaseDate: [{ required: true, message: "璇烽�夋嫨璐疆鏃ユ湡", trigger: "change" }],
+  originalValue: [{ required: true, message: "璇疯緭鍏ヨ祫浜у師鍊�", trigger: "blur" }],
+  usefulLife: [{ required: true, message: "璇疯緭鍏ヤ娇鐢ㄥ勾闄�", trigger: "blur" }],
+};
+
+const totalOriginalValue = computed(() => {
+  return dataList.value.reduce((sum, item) => sum + Number(item.originalValue), 0);
+});
+
+const totalDepreciation = computed(() => {
+  return dataList.value.reduce((sum, item) => sum + Number(item.accumulatedDepreciation), 0);
+});
+
+const totalNetValue = computed(() => {
+  return dataList.value.reduce((sum, item) => sum + Number(item.netValue), 0);
+});
+
+const formatMoney = (value) => {
+  if (value === undefined || value === null) return "0.00";
+  return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+};
+
+const getCategoryLabel = (category) => {
+  const map = {
+    building: "鎴垮眿寤虹瓚",
+    machine: "鏈哄櫒璁惧",
+    vehicle: "杩愯緭宸ュ叿",
+    electronic: "鐢靛瓙璁惧",
+    furniture: "鍔炲叕瀹跺叿",
+  };
+  return map[category] || category;
+};
+
+const getStatusLabel = (status) => {
+  const key = String(status || "").toLowerCase();
+  const map = { in_use: "鍦ㄧ敤", idle: "闂茬疆", repair: "缁翠慨涓�", scrapped: "鎶ュ簾" };
+  return map[key] || status;
+};
+
+const getStatusType = (status) => {
+  const key = String(status || "").toLowerCase();
+  const map = { in_use: "success", idle: "warning", repair: "warning", scrapped: "info" };
+  return map[key] || "";
+};
+
+const calculateNetValue = () => {
+  const originalValue = Number(form.originalValue || 0);
+  const accumulatedDepreciation = Number(form.accumulatedDepreciation || 0);
+  form.netValue = Number((originalValue - accumulatedDepreciation).toFixed(2));
+};
+
+// 鑱旇皟绾﹀畾锛氬垎椤靛弬鏁板浐瀹氫负 current/size锛岃繑鍥� data.records/data.total
+const getTableData = async () => {
+  try {
+    const { data } = await listFixedAssetPage({
+      current: pagination.currentPage,
+      size: pagination.pageSize,
+      assetCode: filters.assetCode,
+      assetName: filters.assetName,
+      category: filters.category,
+      status: filters.status,
+    });
+    dataList.value = data?.records || [];
+    multipleList.value = [];
+    pagination.total = Number(data?.total || 0);
+  } catch (error) {
+    // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
+  }
+};
+
+const handleSelectionChange = (selectionList) => {
+  multipleList.value = selectionList;
+};
+
+const resetFilters = () => {
+  filters.assetCode = "";
+  filters.assetName = "";
+  filters.category = "";
+  filters.status = "";
+  pagination.currentPage = 1;
+  getTableData();
+};
+
+const changePage = ({ current, size }) => {
+  pagination.currentPage = current;
+  pagination.pageSize = size;
+  getTableData();
+};
+
+const add = () => {
+  isEdit.value = false;
+  isView.value = false;
+  currentId.value = null;
+  dialogTitle.value = "鏂板鍥哄畾璧勪骇";
+  Object.assign(form, createDefaultForm(), {
+    purchaseDate: new Date().toISOString().split('T')[0],
+    createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+  });
+  dialogVisible.value = true;
+};
+
+const edit = (row) => {
+  isEdit.value = true;
+  isView.value = false;
+  currentId.value = row.id;
+  dialogTitle.value = "缂栬緫鍥哄畾璧勪骇";
+  Object.assign(form, createDefaultForm(), row);
+  dialogVisible.value = true;
+};
+
+const view = (row) => {
+  edit(row);
+  isView.value = true;
+};
+
+const handleDelete = (row) => {
+  ElMessageBox.confirm("纭鍒犻櫎璇ュ浐瀹氳祫浜у悧锛�", "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(async () => {
+    // 鑱旇皟绾﹀畾锛氬垹闄ゆ帴鍙d娇鐢� ids=1&ids=2
+    await deleteFixedAsset([row.id]);
+    if (dataList.value.length === 1 && pagination.currentPage > 1) {
+      pagination.currentPage -= 1;
+    }
+    ElMessage.success("鍒犻櫎鎴愬姛");
+    await getTableData();
+  });
+};
+
+const handleDepreciation = () => {
+  const ids = selectedIds.value;
+  const confirmText = ids.length
+    ? `纭瀵归�変腑鐨� ${ids.length} 鏉¤祫浜ц繘琛屾湰鏈堟姌鏃ц鎻愬悧锛焋
+    : "纭杩涜鏈湀鎶樻棫璁℃彁鍚楋紵";
+  ElMessageBox.confirm(confirmText, "鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "info",
+  }).then(async () => {
+    await depreciateFixedAsset({ ids });
+    ElMessage.success("鎶樻棫璁℃彁瀹屾垚");
+    await getTableData();
+  });
+};
+
+const handleOut = () => {
+  ElMessage.success("瀵煎嚭鎴愬姛");
+};
+
+const submitForm = () => {
+  if (isView.value) {
+    dialogVisible.value = false;
+    return;
+  }
+  formRef.value.validate(async valid => {
+    if (valid) {
+      try {
+        calculateNetValue();
+        const payload = { ...form };
+        if (isEdit.value) {
+          payload.id = currentId.value;
+          await updateFixedAsset(payload);
+          ElMessage.success("缂栬緫鎴愬姛");
+        } else {
+          await addFixedAsset(payload);
+          ElMessage.success("鏂板鎴愬姛");
+        }
+        dialogVisible.value = false;
+        await getTableData();
+      } catch (error) {
+        // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
+      }
+    }
+  });
+};
+
+onMounted(() => {
+  getTableData();
+});
+</script>
+
+<style lang="scss" scoped>
+.actions {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 15px;
+
+  > div:first-child {
+    display: flex;
+    align-items: center;
+  }
+}
+
+.text-primary {
+  color: #409eff;
+  font-weight: bold;
+}
+
+.text-warning {
+  color: #e6a23c;
+  font-weight: bold;
+}
+
+.text-success {
+  color: #67c23a;
+  font-weight: bold;
+}
+</style>

--
Gitblit v1.9.3