17 小时以前 b5b12cb8d780bff964b0c7f34e2ccbe5b768bde0
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();
});