From b5b12cb8d780bff964b0c7f34e2ccbe5b768bde0 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 13 五月 2026 09:54:38 +0800
Subject: [PATCH] refactor(financial): 优化财务模块组件结构和交互逻辑

---
 src/views/financialManagement/assets/intangibleAssets.vue |   14 ++
 src/views/financialManagement/voucher/index.vue           |  114 ++++++++++++++++++++++-----
 src/views/financialManagement/voucher/detailLedger.vue    |   38 ++++++---
 src/views/financialManagement/assets/fixedAssets.vue      |   14 ++
 src/views/financialManagement/voucher/generalLedger.vue   |   17 +++-
 5 files changed, 149 insertions(+), 48 deletions(-)

diff --git a/src/views/financialManagement/assets/fixedAssets.vue b/src/views/financialManagement/assets/fixedAssets.vue
index 58b2210..c713b52 100644
--- a/src/views/financialManagement/assets/fixedAssets.vue
+++ b/src/views/financialManagement/assets/fixedAssets.vue
@@ -76,7 +76,7 @@
     </div>
 
     <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
-      <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
+      <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">
@@ -178,7 +178,7 @@
         </el-form-item>
       </el-form>
       <template #footer>
-        <el-button type="primary" @click="submitForm">纭畾</el-button>
+        <el-button v-if="!isView" type="primary" @click="submitForm">纭畾</el-button>
         <el-button @click="dialogVisible = false">鍙栨秷</el-button>
       </template>
     </FormDialog>
@@ -231,6 +231,7 @@
 const dialogTitle = ref("");
 const formRef = ref(null);
 const isEdit = ref(false);
+const isView = ref(false);
 const currentId = ref(null);
 
 const createDefaultForm = () => ({
@@ -346,6 +347,7 @@
 
 const add = () => {
   isEdit.value = false;
+  isView.value = false;
   currentId.value = null;
   dialogTitle.value = "鏂板鍥哄畾璧勪骇";
   Object.assign(form, createDefaultForm(), {
@@ -357,6 +359,7 @@
 
 const edit = (row) => {
   isEdit.value = true;
+  isView.value = false;
   currentId.value = row.id;
   dialogTitle.value = "缂栬緫鍥哄畾璧勪骇";
   Object.assign(form, createDefaultForm(), row);
@@ -364,7 +367,8 @@
 };
 
 const view = (row) => {
-  ElMessage.info(`鏌ョ湅璧勪骇: ${row.assetName}`);
+  edit(row);
+  isView.value = true;
 };
 
 const handleDelete = (row) => {
@@ -400,6 +404,10 @@
 };
 
 const submitForm = () => {
+  if (isView.value) {
+    dialogVisible.value = false;
+    return;
+  }
   formRef.value.validate(async valid => {
     if (valid) {
       try {
diff --git a/src/views/financialManagement/assets/intangibleAssets.vue b/src/views/financialManagement/assets/intangibleAssets.vue
index 649ec5b..06b5583 100644
--- a/src/views/financialManagement/assets/intangibleAssets.vue
+++ b/src/views/financialManagement/assets/intangibleAssets.vue
@@ -77,7 +77,7 @@
     </div>
 
     <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false">
-      <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
+      <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">
@@ -171,7 +171,7 @@
         </el-form-item>
       </el-form>
       <template #footer>
-        <el-button type="primary" @click="submitForm">纭畾</el-button>
+        <el-button v-if="!isView" type="primary" @click="submitForm">纭畾</el-button>
         <el-button @click="dialogVisible = false">鍙栨秷</el-button>
       </template>
     </FormDialog>
@@ -224,6 +224,7 @@
 const dialogTitle = ref("");
 const formRef = ref(null);
 const isEdit = ref(false);
+const isView = ref(false);
 const currentId = ref(null);
 
 const createDefaultForm = () => ({
@@ -344,6 +345,7 @@
 
 const add = () => {
   isEdit.value = false;
+  isView.value = false;
   currentId.value = null;
   dialogTitle.value = "鏂板鏃犲舰璧勪骇";
   Object.assign(form, createDefaultForm(), {
@@ -355,6 +357,7 @@
 
 const edit = (row) => {
   isEdit.value = true;
+  isView.value = false;
   currentId.value = row.id;
   dialogTitle.value = "缂栬緫鏃犲舰璧勪骇";
   Object.assign(form, createDefaultForm(), row);
@@ -362,7 +365,8 @@
 };
 
 const view = (row) => {
-  ElMessage.info(`鏌ョ湅璧勪骇: ${row.assetName}`);
+  edit(row);
+  isView.value = true;
 };
 
 const handleDelete = (row) => {
@@ -398,6 +402,10 @@
 };
 
 const submitForm = () => {
+  if (isView.value) {
+    dialogVisible.value = false;
+    return;
+  }
   formRef.value.validate(async valid => {
     if (valid) {
       try {
diff --git a/src/views/financialManagement/voucher/detailLedger.vue b/src/views/financialManagement/voucher/detailLedger.vue
index 202ece1..8ed7dcb 100644
--- a/src/views/financialManagement/voucher/detailLedger.vue
+++ b/src/views/financialManagement/voucher/detailLedger.vue
@@ -2,7 +2,7 @@
   <div class="app-container">
     <el-form :model="filters" :inline="true">
       <el-form-item label="浼氳绉戠洰:">
-        <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code' }" placeholder="璇烽�夋嫨浼氳绉戠洰" clearable style="width: 250px;" filterable />
+        <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code', checkStrictly: true }" placeholder="璇烽�夋嫨浼氳绉戠洰" clearable style="width: 250px;" filterable />
       </el-form-item>
       <el-form-item label="杈呭姪鏍哥畻:">
         <el-select v-model="filters.auxiliary" placeholder="璇烽�夋嫨杈呭姪鏍哥畻" clearable style="width: 180px;">
@@ -86,8 +86,8 @@
   subject: [],
   auxiliary: "",
   auxiliaryItem: "",
-  startMonth: "2024-01",
-  endMonth: "2024-03",
+  startMonth: "",
+  endMonth: "",
 });
 
 const dataList = ref([]);
@@ -99,21 +99,24 @@
   { code: "6602", name: "绠$悊璐圭敤" },
 ];
 
+const toCascaderTree = (nodes = []) =>
+  nodes
+    .filter(item => item.subjectCode && item.subjectName)
+    .map(item => ({
+      code: item.subjectCode,
+      name: item.subjectName,
+      children: toCascaderTree(item.children || []),
+    }));
+
 const loadSubjectOptions = async () => {
   try {
     const { data } = await listAccountSubject({
       current: 1,
       size: 1000,
     });
-    const records = data?.records || [];
-    if (records.length > 0) {
-      subjectOptions.value = records
-        .filter(item => item.subjectCode && item.subjectName)
-        .map(item => ({
-          code: item.subjectCode,
-          name: item.subjectName,
-          children: [],
-        }));
+    const options = toCascaderTree(data?.records || []);
+    if (options.length > 0) {
+      subjectOptions.value = options;
       return;
     }
   } catch (error) {
@@ -158,11 +161,18 @@
 });
 
 const currentSubject = computed(() => {
-  if (!filters.subject || filters.subject.length === 0) return null;
-  const code = filters.subject[filters.subject.length - 1];
+  const code = getSelectedSubjectCode(filters.subject);
+  if (!code) return null;
   return findSubject(subjectOptions.value, code);
 });
 
+const getSelectedSubjectCode = (subjectValue) => {
+  if (Array.isArray(subjectValue)) {
+    return subjectValue.length ? subjectValue[subjectValue.length - 1] : "";
+  }
+  return subjectValue || "";
+};
+
 const findSubject = (options, code) => {
   for (const item of options) {
     if (item.code === code) return item;
diff --git a/src/views/financialManagement/voucher/generalLedger.vue b/src/views/financialManagement/voucher/generalLedger.vue
index b21feac..9ec3ea1 100644
--- a/src/views/financialManagement/voucher/generalLedger.vue
+++ b/src/views/financialManagement/voucher/generalLedger.vue
@@ -2,7 +2,7 @@
   <div class="app-container">
     <el-form :model="filters" :inline="true">
       <el-form-item label="浼氳绉戠洰:">
-        <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code' }" placeholder="璇烽�夋嫨浼氳绉戠洰" clearable style="width: 250px;" filterable />
+        <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code', checkStrictly: true }" placeholder="璇烽�夋嫨浼氳绉戠洰" clearable style="width: 250px;" filterable />
       </el-form-item>
       <el-form-item label="鏈熼棿:">
         <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
@@ -69,8 +69,8 @@
 
 const filters = reactive({
   subject: [],
-  startMonth: "2024-01",
-  endMonth: "2024-03",
+  startMonth: "",
+  endMonth: "",
 });
 
 const dataList = ref([]);
@@ -112,11 +112,18 @@
 };
 
 const currentSubject = computed(() => {
-  if (!filters.subject || filters.subject.length === 0) return null;
-  const code = filters.subject[filters.subject.length - 1];
+  const code = getSelectedSubjectCode(filters.subject);
+  if (!code) return null;
   return findSubject(subjectOptions.value, code);
 });
 
+const getSelectedSubjectCode = (subjectValue) => {
+  if (Array.isArray(subjectValue)) {
+    return subjectValue.length ? subjectValue[subjectValue.length - 1] : "";
+  }
+  return subjectValue || "";
+};
+
 const findSubject = (options, code) => {
   for (const item of options) {
     if (item.code === code) return item;
diff --git a/src/views/financialManagement/voucher/index.vue b/src/views/financialManagement/voucher/index.vue
index 2d34f5c..03c0856 100644
--- a/src/views/financialManagement/voucher/index.vue
+++ b/src/views/financialManagement/voucher/index.vue
@@ -9,9 +9,12 @@
       </el-form-item>
       <el-form-item label="鍒跺崟浜�:">
         <el-select v-model="filters.creator" placeholder="璇烽�夋嫨鍒跺崟浜�" clearable style="width: 150px;">
-          <el-option label="寮犱笁" value="寮犱笁" />
-          <el-option label="鏉庡洓" value="鏉庡洓" />
-          <el-option label="鐜嬩簲" value="鐜嬩簲" />
+          <el-option
+            v-for="item in creatorOptions"
+            :key="item"
+            :label="item"
+            :value="item"
+          />
         </el-select>
       </el-form-item>
       <el-form-item label="鐘舵��:">
@@ -75,25 +78,25 @@
           <h2 class="voucher-title">璁拌处鍑瘉</h2>
           <div class="voucher-period">{{ form.voucherDate ? form.voucherDate.substring(0, 7) + '鏈�' : '' }}</div>
         </div>
-        <el-form :model="form" :rules="rules" ref="formRef" label-width="0">
+        <el-form :model="form" :rules="rules" :disabled="isViewMode" ref="formRef" label-width="0">
           <div class="voucher-info">
             <div class="voucher-no-section">
               <span class="label">鍑瘉瀛楋細</span>
-              <el-select v-model="form.voucherPrefix" style="width: 70px;">
+              <el-select v-model="form.voucherPrefix" :disabled="isViewMode" style="width: 70px;">
                 <el-option label="璁�" value="璁�" />
               </el-select>
-              <el-input v-model="form.voucherNum" style="width: 60px;" />
+              <el-input v-model="form.voucherNum" :disabled="isViewMode" style="width: 60px;" />
               <span class="label" style="margin-left: 5px;">鍙�</span>
             </div>
             <div class="voucher-date-section">
               <span class="label">鏃ユ湡锛�</span>
-              <el-date-picker v-model="form.voucherDate" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 140px;" />
+              <el-date-picker v-model="form.voucherDate" :disabled="isViewMode" type="date" placeholder="閫夋嫨鏃ユ湡" value-format="YYYY-MM-DD" style="width: 140px;" />
             </div>
             <div class="voucher-attachment-section">
               <span class="label">闄勪欢锛�</span>
-              <el-input-number v-model="form.attachmentCount" :min="0" :controls="false" style="width: 60px;" />
+              <el-input-number v-model="form.attachmentCount" :disabled="isViewMode" :min="0" :controls="false" style="width: 60px;" />
               <span class="label" style="margin-left: 5px;">寮�</span>
-              <el-button type="primary" link style="margin-left: 10px;">涓婁紶鏂囦欢</el-button>
+              <el-button type="primary" link :disabled="isViewMode" style="margin-left: 10px;">涓婁紶鏂囦欢</el-button>
             </div>
           </div>
           <div class="voucher-table">
@@ -134,13 +137,14 @@
               <tbody>
                 <tr v-for="(entry, rowIndex) in form.entries" :key="rowIndex" @click="selectRow(rowIndex)" :class="{ 'selected-row': selectedRowIndex === rowIndex }">
                   <td class="col-summary">
-                    <el-input v-model="entry.summary" placeholder="璇疯緭鍏ユ憳瑕�" @focus="selectRow(rowIndex)" />
+                    <el-input v-model="entry.summary" :disabled="isViewMode" placeholder="璇疯緭鍏ユ憳瑕�" @focus="selectRow(rowIndex)" />
                   </td>
                   <td class="col-subject">
                     <el-tree-select
                       v-model="entry.subjectCode"
                       :data="subjectTreeOptions"
                       :props="subjectTreeSelectProps"
+                      :disabled="isViewMode"
                       placeholder="閫夋嫨绉戠洰"
                       filterable
                       check-strictly
@@ -154,7 +158,7 @@
                   <!-- 鍊熸柟11鍒� -->
                   <template v-if="editingCell.row === rowIndex && editingCell.type === 'debit'">
                     <td colspan="11" class="debit-input-cell">
-                      <el-input-number ref="amountInputRef" v-model="entry.debit" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
+                      <el-input-number ref="amountInputRef" v-model="entry.debit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
                     </td>
                   </template>
                   <template v-else>
@@ -165,7 +169,7 @@
                   <!-- 璐锋柟11鍒� -->
                   <template v-if="editingCell.row === rowIndex && editingCell.type === 'credit'">
                     <td colspan="11" class="credit-input-cell">
-                      <el-input-number ref="amountInputRef" v-model="entry.credit" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
+                      <el-input-number ref="amountInputRef" v-model="entry.credit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
                     </td>
                   </template>
                   <template v-else>
@@ -174,7 +178,7 @@
                     </td>
                   </template>
                   <td class="col-action">
-                    <el-button type="danger" link size="small" @click="removeEntry(rowIndex)" icon="Delete" :disabled="form.entries.length <= 2">鍒犻櫎</el-button>
+                    <el-button type="danger" link size="small" @click="removeEntry(rowIndex)" icon="Delete" :disabled="isViewMode || form.entries.length <= 2">鍒犻櫎</el-button>
                   </td>
                 </tr>
                 <tr class="total-row">
@@ -191,19 +195,34 @@
             </table>
           </div>
           <div class="voucher-toolbar">
-            <el-button type="primary" link @click="addEntry" icon="Plus">鏂板琛�</el-button>
+            <el-button type="primary" link @click="addEntry" icon="Plus" :disabled="isViewMode">鏂板琛�</el-button>
           </div>
           <div class="voucher-footer">
             <div class="creator-section">
-              <span class="label">鍒跺崟浜猴細{{ form.creator }}</span>
+              <span class="label">鍒跺崟浜猴細</span>
+              <el-select
+                v-model="form.creator"
+                :disabled="isViewMode"
+                placeholder="璇烽�夋嫨鍒跺崟浜�"
+                filterable
+                clearable
+                style="width: 200px;"
+              >
+                <el-option
+                  v-for="item in creatorOptions"
+                  :key="item"
+                  :label="item"
+                  :value="item"
+                />
+              </el-select>
             </div>
           </div>
         </el-form>
       </div>
       <template #footer>
         <div>
-          <el-button type="primary" @click="submitForm" :disabled="!isBalanced">淇濆瓨</el-button>
-          <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+          <el-button v-if="!isViewMode" type="primary" @click="submitForm" :disabled="!isBalanced">淇濆瓨</el-button>
+          <el-button @click="dialogVisible = false">{{ isViewMode ? '鍏抽棴' : '鍙栨秷' }}</el-button>
         </div>
       </template>
     </FormDialog>
@@ -214,6 +233,8 @@
 import { ref, reactive, onMounted, computed, nextTick } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import useUserStore from "@/store/modules/user";
+import { userListNoPageByTenantId } from "@/api/system/user";
 import { listAccountSubject } from "@/api/financialManagement/accountSubject";
 import {
   listVoucherPage,
@@ -227,6 +248,9 @@
 defineOptions({
   name: "鍑瘉绠$悊",
 });
+
+const userStore = useUserStore();
+const getDefaultCreator = () => userStore.nickName || userStore.name || "寮犱笁";
 
 const filters = reactive({
   voucherNo: "",
@@ -256,8 +280,10 @@
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
 const formRef = ref(null);
+const dialogMode = ref("add");
 const isEdit = ref(false);
 const currentId = ref(null);
+const isViewMode = computed(() => dialogMode.value === "view");
 
 const fallbackSubjectTree = [
   { subjectCode: "1001", subjectName: "搴撳瓨鐜伴噾", balanceDirection: "鍊熸柟", children: [] },
@@ -311,12 +337,24 @@
   voucherDate: "",
   attachmentCount: 0,
   entries: [createEmptyEntry(), createEmptyEntry()],
-  creator: "寮犱笁",
+  creator: getDefaultCreator(),
   remark: "",
 });
 
 const form = reactive({
   ...createDefaultForm(),
+});
+
+const userOptions = ref([]);
+
+const creatorOptions = computed(() => {
+  const source = [
+    ...userOptions.value.map(item => item.nickName || item.userName || item.name),
+    getDefaultCreator(),
+    form.creator,
+    filters.creator,
+  ];
+  return [...new Set(source.filter(Boolean))];
 });
 
 const selectedRowIndex = ref(-1);
@@ -421,6 +459,15 @@
   }
 };
 
+const loadUserOptions = async () => {
+  try {
+    const { data } = await userListNoPageByTenantId();
+    userOptions.value = Array.isArray(data) ? data : [];
+  } catch (error) {
+    userOptions.value = [];
+  }
+};
+
 const resetFilters = () => {
   filters.voucherNo = "";
   filters.dateRange = [];
@@ -437,6 +484,9 @@
 };
 
 const addEntry = () => {
+  if (isViewMode.value) {
+    return;
+  }
   form.entries.push(createEmptyEntry());
 };
 
@@ -445,6 +495,9 @@
 };
 
 const openAmountInput = (index, type) => {
+  if (isViewMode.value) {
+    return;
+  }
   editingCell.row = index;
   editingCell.type = type;
   nextTick(() => {
@@ -491,6 +544,9 @@
 };
 
 const removeEntry = (index) => {
+  if (isViewMode.value) {
+    return;
+  }
   if (form.entries.length <= 2) {
     return;
   }
@@ -509,6 +565,7 @@
 };
 
 const add = () => {
+  dialogMode.value = "add";
   isEdit.value = false;
   currentId.value = null;
   dialogTitle.value = "鏂板鍑瘉";
@@ -523,17 +580,19 @@
   dialogVisible.value = true;
 };
 
-const edit = async row => {
+const openVoucherDialog = async (row, mode = "edit") => {
   try {
-    isEdit.value = true;
+    dialogMode.value = mode;
+    isEdit.value = mode === "edit";
     currentId.value = row.id;
-    dialogTitle.value = "缂栬緫鍑瘉";
+    dialogTitle.value = mode === "view" ? "鏌ョ湅鍑瘉" : "缂栬緫鍑瘉";
     const { data } = await getVoucherDetail(row.id);
     const detail = data || row;
     const parts = (detail.voucherNo || "").split("-");
     Object.assign(form, createDefaultForm(), detail, {
       voucherPrefix: parts[0] || "璁�",
       voucherNum: parts[1] || "",
+      creator: detail.creator || getDefaultCreator(),
       entries:
         detail.entries?.map(item => ({
           subjectCode: item.subjectCode || "",
@@ -556,8 +615,12 @@
   }
 };
 
-const view = (row) => {
-  ElMessage.info(`鏌ョ湅鍑瘉: ${row.voucherNo}`);
+const edit = async row => {
+  await openVoucherDialog(row, "edit");
+};
+
+const view = async row => {
+  await openVoucherDialog(row, "view");
 };
 
 const handlePost = (row) => {
@@ -593,6 +656,10 @@
 };
 
 const submitForm = () => {
+  if (isViewMode.value) {
+    dialogVisible.value = false;
+    return;
+  }
   formRef.value.validate(async valid => {
     if (valid) {
       // 鍓嶇疆鏍¢獙锛氫笌鍚庣瑙勫垯瀵归綈锛屽噺灏戞棤鏁堣姹�
@@ -659,6 +726,7 @@
 };
 
 onMounted(async () => {
+  await loadUserOptions();
   await loadSubjectList();
   await getTableData();
 });

--
Gitblit v1.9.3