yxh
昨天 a79d67f8a9a9fa02f9d25f987b9611af965c484f
src/views/project/fund/performancedetails/index.vue
@@ -6,29 +6,55 @@
      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
        <el-row>
          <el-col :span="5">
            <el-form-item label="申请日期" prop="createTime">
              <el-date-picker clearable style="width: 100%" v-model="form.createTime" type="date"
                value-format="yyyy-MM-dd HH:mm:ss" placeholder="申请日期">
            <el-form-item label="申请日期" prop="applyTime">
              <el-date-picker
                clearable
                style="width: 100%"
                v-model="form.applyTime"
                type="date" format="yyyy-MM-dd"
                value-format="yyyy-MM-dd HH:mm:ss"
                placeholder="申请日期"
                :disabled="true"
              >
              </el-date-picker>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="经办人" prop="username">
              <el-select v-model="form.username" placeholder="申请人" clearable filterable allow-create style="width: 100%"
                @change="getUserAccount">
                <el-option v-for="dict in userlist" :key="dict.index" :label="dict.nickname"
                  :value="dict.nickname"></el-option>
              <el-select
                v-model="form.username"
                placeholder="申请人"
                clearable
                filterable
                allow-create
                style="width: 100%"
                @change="getUserAccount"
              >
                <el-option
                  v-for="dict in userlist"
                  :key="dict.index"
                  :label="dict.nickname"
                  :value="dict.nickname"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="所属组别" prop="deptmentname">
              <el-input v-model="form.deptmentname" placeholder="请输入所属组别" clearable />
              <el-input
                v-model="form.deptmentname"
                placeholder="请输入所属组别"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="组长" prop="managername">
              <el-input v-model="form.managername" placeholder="请输入组长" clearable />
              <el-input
                v-model="form.managername"
                placeholder="请输入组长"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -40,13 +66,26 @@
          </el-col>
          <el-col :span="5">
            <el-form-item label="申请金额" prop="pretaxcost">
              <el-input v-model="form.pretaxcost" placeholder="税前金额合计" :disabled="true" />
              <el-input
                v-model="form.pretaxcost"
                placeholder="税前金额合计"
                :disabled="true"
              />
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="申请材料状态" prop="infoid">
              <el-select v-model="form.checkstatus" filterable placeholder="请选择申请材料状态">
                <el-option v-for="item in baselisttages" :key="item.id" :label="item.name" :value="item.id">
            <el-form-item label="材料预审状态" prop="infoid">
              <el-select
                v-model="form.checkstatus"
                filterable
                placeholder="请选择材料预审状态"
              >
                <el-option
                  v-for="item in baselisttages"
                  :key="item.id"
                  :label="item.name"
                  :value="item.id"
                >
                </el-option>
              </el-select>
            </el-form-item>
@@ -61,129 +100,347 @@
        </el-row>
        <el-row style="margin-top: 5px; margin-bottom: 5px" />
        <el-row v-if="jurisdiction">
          <el-alert title="当前为查看状态,不支持修改存储。" type="warning" show-icon>
          <el-alert
            title="当前为查看状态,不支持修改存储。"
            type="warning"
            show-icon
          >
          </el-alert>
        </el-row>
        <el-row>
          <el-col :span="3">
            <div style="margin-bottom: 15px;">
              <el-button type="success" icon="el-icon-download" @click="Batchentry">批量录入</el-button>
              <el-button
                type="primary"
                icon="el-icon-download"
                size="small"
                @click="Batchentry"
                >批量导入绩效人员</el-button
              >
            </div>
          </el-col>
        </el-row>
        <el-row v-if="userprofile.nickName == '陈慕华' && operationType == 'check'">
          <el-col :span="3">
          <el-col
            :span="3"
            v-if="userprofile.nickName == '陈慕华' && operationType == 'check'"
          >
            <div style="margin-bottom: 15px;">
              <el-button type="success" icon="el-icon-edit-outline" @click="Manualcalculationfn">计算个税</el-button>
              <el-button
                type="success"
                icon="el-icon-edit-outline"
                size="small"
                @click="Manualcalculationfn"
                >计算个税</el-button
              >
            </div>
          </el-col>
        </el-row>
        <el-row>
          <el-table :data="rbDetails" v-loading="loading" max-height="800" border highlight-current-row>
            <el-table-column prop="orderno" align="center" label="序号" width="88">
          <el-table
            :data="rbDetails"
            v-loading="loading"
            max-height="800"
            border
            highlight-current-row
            :summary-method="getSummaries"
            show-summary
          >
            <el-table-column
              prop="orderno"
              align="center"
              label="序号"
              width="88"
              fixed
            >
              <template slot-scope="scope">
                <el-input v-model="scope.row.orderno" placeholder="序号" />
              </template>
            </el-table-column>
            <el-table-column prop="applytype" align="center" label="服务类型" width="200">
            <el-table-column
              prop="applytype"
              align="center"
              label="服务类型"
              width="200"
              fixed
            >
              <template slot-scope="scope">
                <el-select v-model="scope.row.applytype" placeholder="请选择服务类型" @change="verifyFeeItemType(scope.row)">
                  <el-option v-for="dict in rowfeeItemTypes" :key="dict.value" :label="dict.label"
                    :value="dict.value"></el-option>
                <el-select
                  v-model="scope.row.applytype"
                  placeholder="请选择服务类型"
                  @change="verifyFeeItemType(scope.row)"
                >
                  <el-option
                    v-for="dict in rowfeeItemTypes"
                    :key="dict.value"
                    :label="dict.label"
                    :value="dict.value"
                  ></el-option>
                </el-select>
              </template>
            </el-table-column>
            <el-table-column prop="itemid" align="center" label="服务项目" width="260">
            <el-table-column
              prop="itemid"
              align="center"
              label="服务项目"
              width="260"
            >
              <template slot-scope="scope">
                <el-select v-model="scope.row.itemid" placeholder="请选择服务项目" filterable @change="verifyFeeItem(scope.row)"
                  :filter-method="val => searchItemType(val, scope)">
                  <el-option v-for="dict in scope.row.itemlist" :key="dict.id" :label="dict.itemName"
                    :value="dict.id"></el-option>
                <el-select
                  v-model="scope.row.itemid"
                  placeholder="请选择服务项目"
                  filterable
                  @change="verifyFeeItem(scope.row)"
                  :filter-method="val => searchItemType(val, scope)"
                >
                  <el-option
                    v-for="dict in scope.row.itemlist"
                    :key="dict.id"
                    :label="dict.itemName"
                    :value="dict.id"
                  ></el-option>
                </el-select>
                <!-- <el-cascader
                  v-model="scope.row.applytype"
                  :options="aaoptions"
                  :show-all-levels="false"
                ></el-cascader> -->
              </template>
            </el-table-column>
            <el-table-column prop="amount" align="center" label="税前金额" width="120">
            <!-- <el-table-column
              prop="jxrq"
              align="center"
              label="绩效日期"
              width="260"
            >
              <template slot-scope="scope">
                <el-input v-model="scope.row.amount" placeholder="税前金额" @blur="val => {
                  calculateTax(scope.row, 'A');
                }
                  " />
                <el-date-picker
                  v-model="scope.row.jxrq"
                  type="date"
                  placeholder="选择日期"
                >
                </el-date-picker>
              </template>
            </el-table-column> -->
            <el-table-column
              prop="amount"
              align="center"
              label="税前金额"
              width="120"
            >
              <template slot-scope="scope">
                <el-input
                  v-model="scope.row.amount"
                  placeholder="税前金额"
                  @blur="chargeSum"
                />
              </template>
            </el-table-column>
            <el-table-column prop="taxedamount" align="center" label="税后金额" width="120">
            <el-table-column
              prop="taxamount"
              align="center"
              label="扣税金额"
              width="120"
            >
              <template slot-scope="scope">
                <el-input v-model="scope.row.taxedamount" placeholder="税后金额" @blur="val => {
                  calculateTax(scope.row, 'B');
                }
                  " />
                <el-input
                  @blur="chargeSum"
                  v-model="scope.row.taxamount"
                  placeholder="扣税金额"
                />
              </template>
            </el-table-column>
            <el-table-column prop="beneficiaryname" align="center" label="绩效人员或单位" width="250">
            <el-table-column
              prop="taxedamount"
              align="center"
              label="税后金额"
              width="120"
            >
              <template slot-scope="scope">
                <el-button type="primary" plain @click="ShowDetailDialog(scope, 'expert')">{{
                  scope.row.beneficiaryname
                  ? scope.row.beneficiaryname
                  : "点击选择"
                }}</el-button>
              </template>
            </el-table-column>
            <el-table-column prop="idcardno" align="center" label="身份证号" width="200">
              <template slot-scope="scope">
                <el-input v-model="scope.row.idcardno" placeholder="身份证号" />
                <el-input
                  v-model="scope.row.taxedamount"
                  placeholder="税后金额"
                  @blur="queenchargeSum"
                />
              </template>
            </el-table-column>
            <el-table-column prop="depositbank" align="center" label="开户银行" width="200">
            <el-table-column
              prop="beneficiaryname"
              align="center"
              label="绩效人员/单位"
              width="250"
            >
              <template slot-scope="scope">
                <el-input v-model="scope.row.depositbank" placeholder="开户银行" />
                <el-button
                  type="primary"
                  plain
                  @click="ShowDetailDialog(scope, 'expert')"
                  >{{
                    scope.row.beneficiaryname
                      ? scope.row.beneficiaryname
                      : "点击选择"
                  }}</el-button
                >
              </template>
            </el-table-column>
            <el-table-column prop="bankcardno" align="center" label="银行帐号" width="210">
            <el-table-column
              prop="isunit"
              align="center"
              label="人员类别"
              width="100"
            >
              <template slot-scope="scope">
                <el-input v-model="scope.row.bankcardno" placeholder="银行帐号" />
                <el-tag
                  :type="scope.row.isunit == 1 ? 'warning' : 'success'"
                  size="mini"
                  >{{ scope.row.isunit == 1 ? "单位" : "个人" }}</el-tag
                >
              </template>
            </el-table-column>
            <el-table-column prop="remark" align="center" width="330" label="备注">
            <el-table-column
              prop="idcardno"
              align="center"
              label="身份证号"
              width="200"
            >
              <template slot-scope="scope">
                <el-input type="textarea" :rows="2" v-model="scope.row.remark" placeholder="备注" />
                <el-input
                  v-model="scope.row.idcardno"
                  :disabled="scope.row.isunit == 1"
                  :placeholder="
                    scope.row.isunit == 1 ? '单位无需填写' : '身份证号'
                  "
                />
              </template>
            </el-table-column>
            <el-table-column fixed="right" align="center" label="操作" width="180">
            <el-table-column
              prop="depositbank"
              align="center"
              label="开户银行"
              width="200"
            >
              <template slot-scope="scope">
                <el-button type="text" size="mini" @click="addRow(scope.$index)" v-if="operationType == 'add' ||
                  operationType == 'update' ||
                  operationType == 'check'
                  ">新增</el-button>
                <el-button @click.native.prevent="
                  deleteRows(scope.row, scope.$index, rbDetails)
                  " type="text" size="small" v-if="operationType == 'add' ||
    operationType == 'update' ||
    operationType == 'check'
    ">
                <el-input
                  v-model="scope.row.depositbank"
                  placeholder="开户银行"
                />
              </template>
            </el-table-column>
            <el-table-column
              prop="bankcardno"
              align="center"
              label="银行帐号"
              width="210"
            >
              <template slot-scope="scope">
                <el-input
                  v-model="scope.row.bankcardno"
                  placeholder="银行帐号"
                />
              </template>
            </el-table-column>
            <el-table-column
              prop="remark"
              align="center"
              width="330"
              label="备注"
            >
              <template slot-scope="scope">
                <el-input
                  type="textarea"
                  :rows="2"
                  v-model="scope.row.remark"
                  placeholder="备注"
                />
              </template>
            </el-table-column>
            <el-table-column
              fixed="right"
              align="center"
              label="操作"
              width="180"
            >
              <template slot-scope="scope">
                <el-button
                  type="text"
                  size="mini"
                  @click="addRow(scope.$index)"
                  v-if="
                    operationType == 'add' ||
                      operationType == 'update' ||
                      operationType == 'check'
                  "
                  >新增</el-button
                >
                <el-button
                  @click.native.prevent="
                    deleteRows(scope.row, scope.$index, rbDetails)
                  "
                  type="text"
                  size="small"
                  v-if="
                    operationType == 'add' ||
                      operationType == 'update' ||
                      operationType == 'check'
                  "
                >
                  删除
                </el-button>
                <el-button
                  @click.native.prevent="
                    Filepopup(scope.$index, rbDetails, scope.row)
                  "
                  type="text"
                  size="small"
                  >票据</el-button
                >
              </template>
            </el-table-column>
          </el-table>
        </el-row>
        <el-row v-if="operationType == 'detail' ||
          operationType == 'check' ||
          operationType == 'update'
          ">
        <el-row
          v-if="
            operationType == 'detail' ||
              operationType == 'check' ||
              operationType == 'update'
          "
        >
          <el-table :data="fundflowList" border>
            <el-table-column label="审核日期" align="center" width="160" prop="createTime" />
            <el-table-column label="审核人" align="center" width="120" prop="checkusername" />
            <el-table-column label="审核结果" align="center" width="200" prop="flowconclusion">
            <el-table-column
              label="审核日期"
              align="center"
              width="160"
              prop="createTime"
            />
            <el-table-column
              label="审核人"
              align="center"
              width="120"
              prop="checkusername"
            />
            <el-table-column
              label="审核结果"
              align="center"
              width="200"
              prop="flowconclusion"
            >
              <template slot-scope="scope">
                <span v-if="scope.row.flowconclusion == 1">通过</span>
                <span v-if="scope.row.flowconclusion == 2">不通过</span>
              </template>
            </el-table-column>
            <el-table-column label="审核备注" align="center" prop="flowcontent" />
            <el-table-column
              label="审核备注"
              align="center"
              prop="flowcontent"
            />
          </el-table>
        </el-row>
        <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType == 'check'">
        <el-row
          style="margin-top: 25px; margin-bottom: 5px"
          v-if="operationType == 'check'"
        >
          <el-col :span="7">
            <el-form-item label="审核结果" align="left">
              <el-radio-group v-model="checkObj.flowlevelone" align="left">
@@ -202,51 +459,367 @@
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm" v-if="operationType == 'add' ||
          operationType == 'update' ||
          ismanager == true ||
          beforehandType == '1'
          ">提交保存</el-button>
        <el-button type="success" @click="handleup"
          v-if="operationType == 'add' || operationType == 'update'">上报</el-button>
        <el-button type="primary" @click="checksubmit"
          v-if="operationType == 'check' && beforehandType != '1'">提交审核</el-button>
        <el-button
          type="primary"
          @click="submitForm"
          v-if="
            operationType == 'add' ||
              operationType == 'update' ||
              ismanager == true ||
              beforehandType == '1'
          "
          >提交保存</el-button
        >
        <el-button
          type="success"
          @click="handleup"
          v-if="operationType == 'add' || operationType == 'update'"
          >上报</el-button
        >
        <el-button
          type="primary"
          @click="checksubmit"
          v-if="operationType == 'check' && beforehandType != '1'"
          >提交审核</el-button
        >
        <el-button @click="cancel">关 闭</el-button>
      </div>
    </div>
    <el-dialog :visible.sync="showSelectionDialog" :close-on-click-modal="false" :title="'绩效人员(含所在单位)账号选择'" width="500px"
      style="text-align: center" v-loading="loading">
    <el-dialog
      :visible.sync="showSelectionDialog"
      :close-on-click-modal="false"
      :title="'绩效人员(含所在单位)账号选择'"
      width="560px"
      style="text-align: center"
      v-loading="loading"
    >
      <el-form ref="funddetailForm" :model="funddetailForm">
        <el-row>
          <el-form-item label="请输入选择:" prop="unitno" label-width="120px">
          <el-select v-model="funddetailForm.userName" filterable remote reserve-keyword allow-create default-first-option
            placeholder="请输入姓名或单位名称" :remote-method="remoteMethod" :loading="loadingperformance" style="width: 100%">
            <el-option v-for="item in optionsperformance" :key="item.value" :label="item.label" :value="item.value">
            </el-option>
          </el-select>
        </el-form-item>
          <el-form-item label="筛查人员:" prop="userKey" label-width="120px">
            <el-select
              v-model="funddetailForm.userKey"
              filterable
              clearable
              allow-create
              default-first-option
              :filter-method="filterPersonOption"
              placeholder="输入 姓名 / 单位 / 工号 / 身份证后4位 筛查,也可直接输入姓名"
              style="width: 100%"
            >
              <el-option
                v-for="item in optionsperformance"
                :key="item.id"
                :label="personOptionLabel(item)"
                :value="item.id"
              >
                <span style="float: left">{{ item.username }}</span>
                <span style="float: right; color: #8492a6; font-size: 13px">
                  {{
                    item.isUnitPerson ? "单位" : "工号 " + (item.userno || "-")
                  }}{{ item.unitname ? " · " + item.unitname : "" }}
                </span>
              </el-option>
            </el-select>
          </el-form-item>
        </el-row>
        <el-row style="text-align: left; padding-left: 120px">
          <span style="color: #909399; font-size: 12px">
            候选为人员类型含「参与绩效」的人员;选中后身份证号、银行账号等自动带出,单位为单位的行不校验身份证号。
          </span>
        </el-row>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="showSelectionDialog = false">取 消</el-button>
        <el-button type="primary" @click="ConfirmDetailDialog()">确 定</el-button>
        <el-button type="primary" @click="ConfirmDetailDialog()"
          >确 定</el-button
        >
      </span>
    </el-dialog>
    <el-dialog title="提示" :visible.sync="Savereminder" width="30%">
      <el-alert :title="'您已添加' +
        totalquantity +
        '条数据,为防止数据丢失是否提交保存再继续添加。'
        " type="warning">
      <el-alert
        :title="
          '您已添加' +
            totalquantity +
            '条数据,为防止数据丢失是否提交保存再继续添加。'
        "
        type="warning"
      >
      </el-alert>
      <span slot="footer" class="dialog-footer">
        <el-button @click="unsave">取 消</el-button>
        <el-button type="primary" @click="Savenow">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 附件 -->
    <el-dialog
      v-dialogDrags
      :modal="false"
      :close-on-click-modal="false"
      :title="pdftitle"
      :visible.sync="pdfVisible"
      width="60%"
    >
      <div style="margin-bottom: 10px;">
        <el-table :data="tableDatatop" style="width: 100%">
          <el-table-column
            prop="beneficiaryname"
            align="center"
            label="单位/个人"
            width="250"
          >
          </el-table-column>
          <el-table-column
            prop="idcardno"
            align="center"
            label="身份证号"
            width="200"
            v-if="form.applytype == '1' || form.applytype == '2'"
          >
          </el-table-column>
          <el-table-column prop="depositbank" align="center" label="开户银行">
          </el-table-column>
          <el-table-column
            prop="bankcardno"
            align="center"
            label="银行帐号"
            width="210"
          >
          </el-table-column>
        </el-table>
      </div>
      <el-alert
        title="新上传文件需在提交保存后才可进行案例关联,否则视为放弃"
        type="error"
        show-icon
        close-text="知道了"
      >
      </el-alert>
      <el-tabs
        style="margin-top: 20px;"
        v-model="activeName"
        type="border-card"
        @tab-click="handleClick"
      >
        <el-tab-pane label="普通附件" :name="1">
          <div class="pdfimg">
            <div class="box-pdf">
              <div>
                <el-upload
                  size="mini"
                  class="upload-demo"
                  :action="uploadFileUrl"
                  :file-list="fileListto"
                  :show-file-list="false"
                  multiple
                  drag
                  :headers="headers"
                  :on-success="
                    (response, file, fileList) =>
                      uploadSccess(response, file, fileList)
                  "
                  :on-preview="downFile"
                  :disabled="operationType == 'detail'"
                  :on-error="handleUploadError"
                  :on-remove="remove"
                  accept="image/*,.pdf"
                >
                  <i class="el-icon-upload"></i>
                  <div class="el-upload__text">
                    将票据拖到此处,或
                    <em
                      ><el-button
                        :disabled="operationType == 'detail'"
                        size="small"
                        type="primary"
                        >点击上传</el-button
                      ></em
                    >
                  </div>
                </el-upload>
                <el-table
                  :data="fileListto"
                  @row-click="downFile"
                  style="width: 100%"
                  height="400"
                >
                  <el-table-column
                    prop="name"
                    :show-overflow-tooltip="true"
                    label="名称"
                  >
                    <template slot-scope="scope">
                      <i style="color:#409EFF" class=" el-icon-s-order" />
                      <span>{{ scope.row.name }}</span>
                    </template>
                  </el-table-column>
                  <el-table-column
                    prop="name"
                    width="190"
                    :show-overflow-tooltip="true"
                    label="功能"
                  >
                    <template slot-scope="scope">
                      <el-button
                        type="danger"
                        size="mini"
                        @click.native.prevent.stop="deletedowfile(scope.row)"
                        >删除</el-button
                      >
                      <el-button
                        type="primary"
                        size="mini"
                        @click.native.prevent.stop="moveupdowfile(scope.row)"
                        >上移</el-button
                      >
                      <el-button
                        type="success"
                        size="mini"
                        icon="el-icon-search"
                        circle
                        @click.native.prevent.stop="Downloadfile(scope.row)"
                      ></el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
            </div>
            <div
              v-if="this.previewpdf && pdfimgsrcList.length"
              class="pdfimgmin"
            >
              <el-image
                style="width: 95%; height: 90%"
                :src="pdfimg"
                @click="handleImageClick(0)"
              />
              <custom-image-viewer
                :url-list="pdfimgsrcList"
                :initial-index="currentIndex"
                :visible="viewerVisible"
                @update:visible="viewerVisible = $event"
                @close="handleViewerClose"
              />
            </div>
            <div v-else class="pdfimgmins">{{ hintitle }}</div>
          </div>
        </el-tab-pane>
        <el-tab-pane label="发票文件" :name="2">
          <div class="pdfimg">
            <div class="box-pdf">
              <div>
                <el-upload
                  size="mini"
                  class="upload-demo"
                  :action="uploadFileUrl"
                  :file-list="invoicefileList"
                  :show-file-list="false"
                  multiple
                  drag
                  :headers="headers"
                  :on-success="
                    (response, file, fileList) =>
                      uploadSccess(response, file, fileList)
                  "
                  :on-preview="downFile"
                  :disabled="operationType == 'detail'"
                  :on-error="handleUploadError"
                  :on-remove="remove"
                  accept="image/*,.pdf"
                >
                  <i class="el-icon-upload"></i>
                  <div class="el-upload__text">
                    将发票文件拖到此处,或
                    <em
                      ><el-button
                        :disabled="operationType == 'detail'"
                        size="small"
                        type="primary"
                        >点击上传</el-button
                      ></em
                    >
                  </div>
                </el-upload>
                <el-table
                  :data="invoicefileListto"
                  @row-click="downFile"
                  style="width: 100%"
                  height="400"
                >
                  <el-table-column
                    prop="name"
                    :show-overflow-tooltip="true"
                    label="名称"
                  >
                    <template slot-scope="scope">
                      <i style="color:#409EFF" class=" el-icon-s-order" />
                      <span>{{ scope.row.name }}</span>
                    </template>
                  </el-table-column>
                  <el-table-column
                    prop="name"
                    width="190"
                    :show-overflow-tooltip="true"
                    label="功能"
                  >
                    <template slot-scope="scope">
                      <el-button
                        type="primary"
                        size="mini"
                        @click.native.prevent.stop="deletedowfile(scope.row)"
                        >删除</el-button
                      >
                      <el-button
                        type="primary"
                        size="mini"
                        @click.native.prevent.stop="moveupdowfile(scope.row)"
                        >上移</el-button
                      >
                      <el-button
                        type="success"
                        size="mini"
                        icon="el-icon-search"
                        circle
                        @click.native.prevent.stop="Downloadfile(scope.row)"
                      ></el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
            </div>
            <div
              v-if="this.previewpdf && invoicepdfimgsrcList.length"
              class="pdfimgmin"
            >
              <el-image
                style="width: 95%; height: 90%"
                :src="invoicepdfimg"
                @click="invoiceHandleImageClick(0)"
              />
              <custom-image-viewer
                :url-list="invoicepdfimgsrcList"
                :initial-index="invoiceCurrentIndex"
                :visible="invoiceViewerVisible"
                @update:visible="invoiceViewerVisible = $event"
                @close="invoiceHandleViewerClose"
              />
            </div>
            <div v-else class="pdfimgmins">{{ hintitle }}</div>
          </div>
        </el-tab-pane>
      </el-tabs>
    </el-dialog>
    <!-- 批量选取 -->
    <el-dialog title="批量生成明细信息" :visible.sync="batchdialogVisible" width="40%">
    <el-dialog
      title="批量生成明细信息"
      :visible.sync="batchdialogVisible"
      width="40%"
    >
      <div style="margin-bottom: 15px; margin-left: 10px;">
        <el-radio-group v-model="Performanceclass">
          <el-radio-button :label="68">月度绩效</el-radio-button>
@@ -254,12 +827,39 @@
          <el-radio-button :label="70">年度绩效</el-radio-button>
        </el-radio-group>
      </div>
      <div style="margin-bottom: 12px; margin-left: 10px;">
        <el-input
          v-model="personKeyword"
          clearable
          size="small"
          prefix-icon="el-icon-search"
          placeholder="输入 姓名 / 单位 / 工号 / 身份证后4位 筛查"
          style="width: 330px"
        />
        <span style="margin-left: 10px; color: #909399; font-size: 12px">
          共 {{ filteredCityOptions.length }} 人
        </span>
      </div>
      <div style="max-height: 330px; overflow-y: auto">
        <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
        <el-checkbox
          :indeterminate="isIndeterminate"
          v-model="checkAll"
          @change="handleCheckAllChange"
          >全选(当前筛查结果)</el-checkbox
        >
        <div style="margin: 15px 0;"></div>
        <el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
          <el-checkbox border v-for="city in cityOptions" :label="city" :key="city.userNo">{{ city.userName
          }}</el-checkbox>
        <el-checkbox-group
          v-model="checkedCities"
          @change="handleCheckedCitiesChange"
        >
          <el-checkbox
            border
            v-for="city in filteredCityOptions"
            :label="city"
            :key="city.id"
            >{{ city.username }}{{ city.isUnitPerson ? "(单位)" : ""
            }}{{ city.unitname ? " · " + city.unitname : "" }}</el-checkbox
          >
        </el-checkbox-group>
      </div>
@@ -302,7 +902,6 @@
  listOrganization,
  getOrganization,
  listReportname,
  listperformance,
  listUser
} from "@/api/project/organization";
@@ -319,12 +918,16 @@
import Li_area_select from "@/components/Address";
import OrgSelecter from "@/views/project/components/orgselect";
import { getToken } from "@/utils/auth";
import { moneySum, moneyAdd, moneySub, moneyRound } from "@/utils/money";
import { checkFileName, checkDetails } from "@/utils/fileNameCheck";
import CustomImageViewer from "@/components/CustomImageViewer";
export default {
  //import引入的组件需要注入到对象中才能使用
  components: {
    Li_area_select,
    OrgSelecter
    OrgSelecter,
    CustomImageViewer
  },
  name: "fundApply",
@@ -371,13 +974,17 @@
      feeUnitList: [],
      batchdialogVisible: false,
      itemlist: [],
      //绩效人员候选(人员类型含「参与绩效」的人员,来自 service_externalperson)
      cityOptions: [],
      //批量录入弹框的筛查关键字
      personKeyword: "",
      checkAll: false,
      checkedCities: [],
      Personnelforname: null,
      unitforname: null,
      isIndeterminate: true,
      Performanceclass: 68,
      ICDtoken: getToken(),
      //是否是专家费的OPO审批人员
      ismanager: false,
@@ -386,15 +993,15 @@
      baselisttages: [
        {
          id: 1,
          name: "待申请材料"
          name: "待审核"
        },
        {
          id: 2,
          name: "审核通过等待邮寄纸质材料"
          name: "预审通过等待纸质材料"
        },
        {
          id: 3,
          name: "已收到报销材料"
          name: "已收到纸质材料"
        }
      ],
      PerformanceType: [
@@ -432,7 +1039,52 @@
      //行记录的费用类型数组
      rowfeeItemTypes: [{ label: "管理成本", value: "9" }],
      aaoptions: [
        {
          value: "niandu",
          label: "年度"
        },
        {
          value: "jidu",
          label: "季度",
          children: [
            {
              value: "2024-03-31",
              label: "第一季度"
            },
            {
              value: "2024-6-30",
              label: "第二季度"
            },
            {
              value: "2024-9-30",
              label: "第三季度"
            },
            {
              value: "2024-12-31",
              label: "第四季度"
            }
          ]
        },
        {
          value: "yuedu",
          label: "月度",
          children: [
            { label: "一月", value: new Date(2024, 0 + 1, 0).getDate() },
            { label: "二月", value: new Date(2024, 1 + 1, 0).getDate() },
            { label: "三月", value: new Date(2024, 2 + 1, 0).getDate() },
            { label: "四月", value: new Date(2024, 3 + 1, 0).getDate() },
            { label: "五月", value: new Date(2024, 4 + 1, 0).getDate() },
            { label: "六月", value: new Date(2024, 5 + 1, 0).getDate() },
            { label: "七月", value: new Date(2024, 6 + 1, 0).getDate() },
            { label: "八月", value: new Date(2024, 7 + 1, 0).getDate() },
            { label: "九月", value: new Date(2024, 8 + 1, 0).getDate() },
            { label: "十月", value: new Date(2024, 9 + 1, 0).getDate() },
            { label: "十一月", value: new Date(2024, 10 + 1, 0).getDate() },
            { label: "十二月", value: new Date(2024, 11 + 1, 0).getDate() }
          ]
        }
      ],
      //费用说明
      feeBlocks: [],
@@ -448,9 +1100,6 @@
      // 表单校验
      rules: {
        createTime: [
          { required: true, message: "请输入填报日期", trigger: "blur" }
        ],
        reason: [
          { required: true, message: "请输入出差事由", trigger: "blur" }
        ],
@@ -461,6 +1110,7 @@
      funddetailForm: {
        index: null,
        userKey: null,
        userName: null,
        beneficiaryname: null,
        beneficiaryno: null,
@@ -508,6 +1158,8 @@
        flowconclusion: null,
        fundid: null
      },
      // 网络请求头
      Networkheader: null,
      // 查询参数
      queryParams: {
@@ -560,12 +1212,30 @@
        usestate: null
      },
      //附件列表
      fileList: [],
      fileListto: [],
      invoicefileList: [],
      invoicefileListto: [],
      invoicepdfimg: "",
      invoicepdfimgsrcList: [],
      activeName: 1, //文件类型
      //上传附件路径
      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload",
      //文件上传token
      headers: {
        Authorization: "Bearer " + getToken()
      },
      //票据文件
      pdftitle: "",
      pdfimg: "",
      pdfimgsrcList: [],
      pdfVisible: false,
      previewpdf: false,
      viewerVisible: false,
      currentIndex: 0,
      invoiceViewerVisible: false,
      invoiceCurrentIndex: 0,
      hintitle: "请上传文件后查看",
      atpresent: "",
      Savereminder: false, //提醒保存弹框
@@ -576,18 +1246,27 @@
  },
  //监听属性 类似于data概念
  computed: {},
  computed: {
    //批量录入弹框:按关键字(姓名/单位/工号/身份证后4位)筛查后的候选人
    filteredCityOptions() {
      const kw = (this.personKeyword || "").trim().toLowerCase();
      if (!kw) {
        return this.cityOptions;
      }
      return this.cityOptions.filter(item => this.personMatchKeyword(item, kw));
    }
  },
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {
    bbaaccss(val) { },
    bbaaccss(val) {},
    // 浏览器页面关闭或刷新提示
    beforeunloadHandler(e) {
      if (
        (JSON.stringify(this.form) == sessionStorage.getItem("apiform") &&
          JSON.stringify(this.rbDetails) ==
          sessionStorage.getItem("apifunddetail")) ||
            sessionStorage.getItem("apifunddetail")) ||
        !sessionStorage.getItem("apifunddetail")
      ) {
      } else {
@@ -772,7 +1451,10 @@
            }
            sessionStorage.removeItem("apifunddetail");
            sessionStorage.setItem("apifunddetail", JSON.stringify(this.rbDetails));
            sessionStorage.setItem(
              "apifunddetail",
              JSON.stringify(this.rbDetails)
            );
          } else {
            this.addRow(0);
          }
@@ -888,7 +1570,7 @@
    handleDelete() {
      this.$modal
        .confirm("是否确认删除该记录?")
        .then(function () {
        .then(function() {
          return delFund(this.curId);
        })
        .then(() => {
@@ -901,7 +1583,7 @@
          this.getfundList();
          this.$modal.msgSuccess("删除成功");
        })
        .catch(() => { });
        .catch(() => {});
    },
    /** 上报按钮操作 */
@@ -909,7 +1591,7 @@
      if (
        (JSON.stringify(this.form) == sessionStorage.getItem("apiform") &&
          JSON.stringify(this.rbDetails) ==
          sessionStorage.getItem("apifunddetail")) ||
            sessionStorage.getItem("apifunddetail")) ||
        !sessionStorage.getItem("apifunddetail")
      ) {
      } else {
@@ -926,7 +1608,18 @@
          //判断是否存在上报记录
          this.form.recordstatus = 0;
          var currenttime = new Date();
          this.form.createTime = currenttime.getFullYear() + "-" + (currenttime.getMonth()+1) + "-" + currenttime.getDate() + " " + currenttime.getHours() + ":" + currenttime.getMinutes() + ":" + currenttime.getSeconds();
          this.form.applyTime =
            currenttime.getFullYear() +
            "-" +
            (currenttime.getMonth() + 1) +
            "-" +
            currenttime.getDate() +
            " " +
            currenttime.getHours() +
            ":" +
            currenttime.getMinutes() +
            ":" +
            currenttime.getSeconds();
          if (!this.form.id) {
            this.form.id = this.$route.query.id;
@@ -967,7 +1660,12 @@
      return randomString;
    },
    /** 提交按钮 */
    submitForm: debounce(function () {
    submitForm: debounce(function() {
      // 2026-10-15:保存前附件文件名规范校验(仅新增单据;老单据的历史附件由后端按"只校验本次变更"放行)
      if (!this.checkDetailFileNames()) {
        return;
      }
      if (!this.randomnumber) {
        this.randomnumber = this.generateRandomString(9);
        this.form.randomnumber = this.randomnumber;
@@ -983,16 +1681,21 @@
            if (tempDetail.itemid == null) {
              this.$modal.msgWarning(
                "服务项目表中,第" +
                (k + 1).toString() +
                "行的服务项目未选择,请先选择服务项目后再提交保存!"
                  (k + 1).toString() +
                  "行的服务项目未选择,请先选择服务项目后再提交保存!"
              );
              return;
            }
            if (tempDetail.idcardno == null) {
            // 单位行(isunit=1)不需要身份证号
            if (
              tempDetail.isunit != 1 &&
              (tempDetail.idcardno == null ||
                String(tempDetail.idcardno).trim() === "")
            ) {
              this.$modal.msgWarning(
                "服务项目表中,第" +
                (k + 1).toString() +
                "行的身份证未完善,请先填写身份证后再提交保存!"
                  (k + 1).toString() +
                  "行的身份证未完善,请先填写身份证后再提交保存!"
              );
              return;
            }
@@ -1001,8 +1704,8 @@
              if (tempDetail.servicesscope == null) {
                this.$modal.msgWarning(
                  "服务项目表中,第" +
                  (k + 1).toString() +
                  "行的费用说明未选择,请选择费用说明后再提交保存!"
                    (k + 1).toString() +
                    "行的费用说明未选择,请选择费用说明后再提交保存!"
                );
                return;
              }
@@ -1010,12 +1713,28 @@
              if (tempDetail.beneficiaryno == null) {
                this.$modal.msgWarning(
                  "服务项目表中,第" +
                  (k + 1).toString() +
                  "行的服务人员姓名为选择,请选择人员后再提交保存!"
                    (k + 1).toString() +
                    "行的服务人员姓名为选择,请选择人员后再提交保存!"
                );
                return;
              }
            }
          }
          //明细重复校验:同一人员/单位不允许出现多行
          const detailNameMap = {};
          for (let k = 0; k < this.rbDetails.length; k++) {
            const nm = String(this.rbDetails[k].beneficiaryname || "").trim();
            if (!nm) {
              continue;
            }
            if (detailNameMap[nm]) {
              this.$modal.msgWarning(
                "服务项目表中,人员名称:" + nm + " 重复,请核对后再提交保存!"
              );
              return;
            }
            detailNameMap[nm] = true;
          }
          //处理明细
@@ -1057,8 +1776,8 @@
              ) {
                this.$modal.msgWarning(
                  "服务项目表中,第" +
                  (j + 1).toString() +
                  "行的金额未输入,请先输入金额后再提交保存!"
                    (j + 1).toString() +
                    "行的金额未输入,请先输入金额后再提交保存!"
                );
                return;
              }
@@ -1072,8 +1791,8 @@
              ) {
                this.$modal.msgWarning(
                  "服务项目表中,第" +
                  (j + 1).toString() +
                  "行的金额未输入,请先输入金额后再提交保存!"
                    (j + 1).toString() +
                    "行的金额未输入,请先输入金额后再提交保存!"
                );
                return;
              }
@@ -1100,6 +1819,19 @@
          if (this.form.id != null) {
          } else {
            this.form.recordstatus = -1;
            var currenttime = new Date();
            this.form.applyTime =
              currenttime.getFullYear() +
              "-" +
              (currenttime.getMonth() + 1) +
              "-" +
              currenttime.getDate() +
              " " +
              currenttime.getHours() +
              ":" +
              currenttime.getMinutes() +
              ":" +
              currenttime.getSeconds();
          }
          sessionStorage.setItem(
@@ -1148,12 +1880,19 @@
        flowconclusion: this.checkObj.flowlevelone,
        flowcontent: this.checkObj.flowconclusion
      };
      this.$modal.loading("正在提交审核,请稍候!");
      checkfund(checkFundObj).then(res => {
        //关闭窗口
        this.reset();
        this.$modal.msgSuccess("审核完成!");
        this.$store.dispatch("tagsView/delView", this.$route);
        this.$router.go(-1);
        if (res.code == 200) {
          //关闭窗口
          this.reset();
          this.$modal.closeLoading();
          this.$modal.msgSuccess("审核完成!");
          this.$store.dispatch("tagsView/delView", this.$route);
          this.$router.go(-1);
        } else {
          this.$modal.closeLoading();
          this.$modal.msgError(res.msg || "操作失败");
        }
      });
    },
@@ -1171,7 +1910,7 @@
        this.standardlevel = res.data.standardlevel;
        if (
          this.userprofile.userName == "admin" ||
          this.userprofile.userName == "001" ||
          this.userprofile.userName == "053" ||
          this.userprofile.userName == "047"
        ) {
          this.ismanager = true;
@@ -1205,7 +1944,7 @@
        this.personlist = res.rows;
        for (let j = 0; j < this.personlist.length; j++) {
          //获取费用报销机构列表
          if (this.personlist[j].usertype == "org") {
          if (this.hasUserType(this.personlist[j].usertype, "org")) {
            this.feeUnitList.push({
              id: this.personlist[j].id,
              reportNo: this.personlist[j].userno,
@@ -1216,7 +1955,7 @@
            });
          }
          //专家人员列表
          else if (res.rows[j].usertype == "expert") {
          else if (this.hasUserType(res.rows[j].usertype, "expert")) {
            this.expertlist.push({
              expertNo: this.personlist[j].id,
              exportName: this.personlist[j].username
@@ -1405,17 +2144,38 @@
      }
    },
    //计算金额
    calculateTax(row, type) {
      let targetValue = 0;
    //税前扣税算税后(金额一律走精确运算)
    chargeSum(row, type) {
      for (let i = 0; i < this.rbDetails.length; i++) {
        if (!this.rbDetails[i].amount) {
          this.rbDetails[i].amount = 0;
        }
        targetValue += parseFloat(this.rbDetails[i].amount); // 假设每个对象中的特定值存储在'specificValue'属性下
        if (!this.rbDetails[i].taxamount) {
          this.rbDetails[i].taxamount = 0;
        }
        //税前 - 扣税 = 税后(浮点相减会残留极小尾差,导致出现 -0.00)
        this.rbDetails[i].taxedamount = moneySub(
          this.rbDetails[i].amount,
          this.rbDetails[i].taxamount
        ).toFixed(2);
      }
      console.log(targetValue, "合计");
      this.form.pretaxcost = targetValue;
      //合计必须精确累加,否则会写入 form.pretaxcost 并落库
      this.form.pretaxcost = moneySum(this.rbDetails, "amount");
    },
    //税后扣税算税前(金额一律走精确运算)
    queenchargeSum(row, type) {
      for (let i = 0; i < this.rbDetails.length; i++) {
        if (!this.rbDetails[i].amount) {
          this.rbDetails[i].amount = 0;
        }
        if (!this.rbDetails[i].taxamount) {
          this.rbDetails[i].taxamount = 0;
        }
        //扣税 + 税后 = 税前(必须精确相加并归一化到 2 位,否则会残留长小数)
        this.rbDetails[i].amount = moneyRound(
          moneyAdd(this.rbDetails[i].taxamount, this.rbDetails[i].taxedamount)
        );
      }
    },
    unsave() {
@@ -1424,6 +2184,11 @@
    },
    // 接受提醒立刻保存
    Savenow() {
      // 2026-10-15:保存前附件文件名规范校验(仅新增单据;老单据的历史附件由后端按"只校验本次变更"放行)
      if (!this.checkDetailFileNames()) {
        return;
      }
      if (!this.randomnumber) {
        this.randomnumber = this.generateRandomString(9);
        this.form.randomnumber = this.randomnumber;
@@ -1444,8 +2209,8 @@
            if (tempDetail.itemid == null) {
              this.$modal.msgWarning(
                "服务项目表中,第" +
                (k + 1).toString() +
                "行的服务项目未选择,请先选择服务项目后再提交保存!"
                  (k + 1).toString() +
                  "行的服务项目未选择,请先选择服务项目后再提交保存!"
              );
              return;
            }
@@ -1454,8 +2219,8 @@
              if (tempDetail.servicesscope == null) {
                this.$modal.msgWarning(
                  "服务项目表中,第" +
                  (k + 1).toString() +
                  "行的费用说明未选择,请选择费用说明后再提交保存!"
                    (k + 1).toString() +
                    "行的费用说明未选择,请选择费用说明后再提交保存!"
                );
                return;
              }
@@ -1463,12 +2228,28 @@
              if (tempDetail.beneficiaryno == null) {
                this.$modal.msgWarning(
                  "服务项目表中,第" +
                  (k + 1).toString() +
                  "行的服务人员姓名为选择,请选择人员后再提交保存!"
                    (k + 1).toString() +
                    "行的服务人员姓名为选择,请选择人员后再提交保存!"
                );
                return;
              }
            }
          }
          //明细重复校验:同一人员/单位不允许出现多行
          const detailNameMap = {};
          for (let k = 0; k < this.rbDetails.length; k++) {
            const nm = String(this.rbDetails[k].beneficiaryname || "").trim();
            if (!nm) {
              continue;
            }
            if (detailNameMap[nm]) {
              this.$modal.msgWarning(
                "服务项目表中,人员名称:" + nm + " 重复,请核对后再提交保存!"
              );
              return;
            }
            detailNameMap[nm] = true;
          }
          //处理明细
@@ -1509,8 +2290,8 @@
            ) {
              this.$modal.msgWarning(
                "服务项目表中,第" +
                (j + 1).toString() +
                "行的金额未输入,请先输入金额后再提交保存!"
                  (j + 1).toString() +
                  "行的金额未输入,请先输入金额后再提交保存!"
              );
              return;
            }
@@ -1557,16 +2338,18 @@
        }
      });
    },
    // 全选
    // 全选(按当前筛查结果)
    handleCheckAllChange(val) {
      this.checkedCities = val ? this.cityOptions : [];
      this.checkedCities = val ? this.filteredCityOptions.slice() : [];
      this.isIndeterminate = false;
    },
    handleCheckedCitiesChange(value) {
      let checkedCount = value.length;
      this.checkAll = checkedCount === this.cityOptions.length;
      this.checkAll =
        this.filteredCityOptions.length > 0 &&
        checkedCount === this.filteredCityOptions.length;
      this.isIndeterminate =
        checkedCount > 0 && checkedCount < this.cityOptions.length;
        checkedCount > 0 && checkedCount < this.filteredCityOptions.length;
    },
    // 手动计算
    Manualcalculationfn() {
@@ -1591,18 +2374,107 @@
    },
    // 批量录入点击
    Batchentry() {
      // ethical
      this.listperformance();
      this.personKeyword = "";
      this.checkedCities = [];
      this.checkAll = false;
      this.isIndeterminate = false;
      this.batchdialogVisible = true;
    },
    /**
     * 载入绩效人员候选。
     * 改造前取自人员分组表(service_externalperson_group,group_id=1);
     * 2026-09-27 起改为「人员类型(UserType,可多选)含 参与绩效」的外围人员账户,
     * 不再依赖分组表。
     */
    listperformance() {
      listperformance(1).then(res => {
        this.cityOptions = res.data;
        this.listperformancea = [];
        this.listperformancea = this.cityOptions.map(item => {
          return { value: item.userName, label: item.userName };
        });
      listExternalperson({
        usertype: "performance",
        pageNum: 1,
        pageSize: 10000
      }).then(res => {
        const rows = res.rows || [];
        this.cityOptions = rows
          //只保留启用账号(与改造前分组表接口的 userstatus=1 口径一致)。
          //注意:ServiceExternalperson 实体没有 del_flag 字段,接口不返回该字段,
          //不能用它做过滤,否则 undefined == 0 会把全部候选人滤空。
          .filter(
            item =>
              item.userstatus === undefined ||
              item.userstatus === null ||
              item.userstatus == 1
          )
          .map(item => {
            return Object.assign({}, item, {
              isUnitPerson: this.hasUserType(item.usertype, "org")
            });
          });
      });
    },
    /** 人员类型(多值,逗号分隔)是否包含指定类型 */
    hasUserType(usertype, code) {
      if (!usertype) {
        return false;
      }
      return (
        String(usertype)
          .split(",")
          .map(t => t.trim())
          .indexOf(code) > -1
      );
    },
    /** 关键字命中判断:姓名 / 单位 / 工号 / 身份证后4位 */
    personMatchKeyword(item, kw) {
      const idcard = String(item.idcardno || "");
      return (
        String(item.username || "")
          .toLowerCase()
          .indexOf(kw) > -1 ||
        String(item.unitname || "")
          .toLowerCase()
          .indexOf(kw) > -1 ||
        String(item.userno || "")
          .toLowerCase()
          .indexOf(kw) > -1 ||
        (idcard.length >= 4 && idcard.slice(-4).indexOf(kw) > -1)
      );
    },
    /** 识别人员类别:单位(人员类型含 org)还是个人 */
    isUnitPerson(item) {
      return !!(item && this.hasUserType(item.usertype, "org"));
    },
    /** 选择框下拉项文案:姓名(单位) */
    personOptionLabel(item) {
      return (
        (item.username || "") +
        (item.unitname ? "(" + item.unitname + ")" : "") +
        (item.isUnitPerson ? " - 单位" : "")
      );
    },
    /** 选择框候选:空关键字返回全部,否则按关键字筛查 */
    filterPersonCandidates(kw) {
      if (!kw) {
        return this.cityOptions.slice();
      }
      return this.cityOptions.filter(item => this.personMatchKeyword(item, kw));
    },
    /** 选择框本地筛查(姓名/单位/工号/身份证后4位) */
    filterPersonOption(query) {
      const kw = (query || "").trim().toLowerCase();
      this.optionsperformance = this.filterPersonCandidates(kw);
      // 已选中项要保留在下拉里,否则回显会空白
      const picked = this.getPickedPerson(this.funddetailForm.userKey);
      if (picked && this.optionsperformance.indexOf(picked) === -1) {
        this.optionsperformance = [picked].concat(this.optionsperformance);
      }
    },
    /** 按唯一键(人员 ID)取候选;手工输入的姓名返回 null */
    getPickedPerson(key) {
      if (key === null || key === undefined || key === "") {
        return null;
      }
      return (
        this.cityOptions.find(item => String(item.id) === String(key)) || null
      );
    },
    // 确认录入
    BatchentryFn() {
@@ -1610,23 +2482,42 @@
      if (!this.rbDetails[0].applytype) {
        this.rbDetails = [];
      }
      // 明细中已有的人员姓名,用于重复提醒(与伦理专家费页的判重口径一致)
      const existed = {};
      this.rbDetails.forEach(row => {
        if (row.beneficiaryname) {
          existed[String(row.beneficiaryname).trim()] = true;
        }
      });
      const duplicated = [];
      this.checkedCities.forEach(item => {
        const nameKey = String(item.username || "").trim();
        if (nameKey && existed[nameKey]) {
          duplicated.push(item.username);
          return;
        }
        if (nameKey) {
          existed[nameKey] = true;
        }
        const isunit = this.isUnitPerson(item);
        let rowData = {
          orderno: null,
          fundid: null,
          beneficiaryname: item.userName,
          beneficiaryno: item.usertNo,
          beneficiaryname: item.username,
          beneficiaryno: item.userno,
          isunit: isunit ? 1 : 0,
          unitname: item.unitname,
          unitno: null,
          unitno: item.unitno,
          uintuserno: null,
          title: item.title,
          idcardtype: null,
          idcardno: item.idcrad,
          idcardno: isunit ? "" : item.idcardno,
          sex: null,
          familyrelations: null,
          phone: null,
          depositbank: item.depositBank,
          bankcardno: item.bankCardNo,
          phone: item.telephone,
          depositbank: item.depositbank,
          bankcardno: item.bankcardno,
          branchbankname: item.branchbankname,
          annexbankcard: null,
          annexregistform: null,
@@ -1669,6 +2560,11 @@
      this.calculateTax();
      this.batchdialogVisible = false;
      this.checkedCities = [];
      if (duplicated.length) {
        this.$modal.msgWarning(
          "以下人员在明细中已存在,已跳过重复添加:" + duplicated.join("、")
        );
      }
      console.log(this.rowfeeItemTypes);
    },
    //新增一行
@@ -1679,6 +2575,7 @@
        fundid: null,
        beneficiaryname: null,
        beneficiaryno: null,
        isunit: 0,
        unitname: null,
        unitno: null,
        uintuserno: null,
@@ -1778,64 +2675,482 @@
        });
      //全部删除后添加一条新行
    },
    //专家/医疗机构/费用报销机构选择
    //绩效人员/单位选择:打开时预填当前行已选人员,避免"直接确定"把已有姓名清空
    ShowDetailDialog(spoce, showType) {
      this.spocewl = spoce;
      this.selectionType = showType;
      this.selectionType = this.experthear;
      this.expertfrom = "1";
      this.funddetailForm.index = spoce.$index;
      this.funddetailForm.beneficiaryno = spoce.row.beneficiaryno;
      this.funddetailForm.beneficiaryname = spoce.row.beneficiaryname;
      this.funddetailForm.unitno = spoce.row.unitno;
      this.funddetailForm.unitname = spoce.row.unitname;
      this.funddetailForm.expertname = "";
      this.funddetailForm.expertidcardno = "";
      this.funddetailForm.expertunitno = "";
      this.funddetailForm.expertunitname = "";
      this.funddetailForm.experttitle = "";
      this.funddetailForm.expertdepositbank = "";
      this.funddetailForm.expertbankcardno = "";
      //当前行已选人员的回填:先按人员编号匹配,匹配不到再按姓名匹配
      let cur =
        this.cityOptions.find(
          item => String(item.userno) === String(spoce.row.beneficiaryno)
        ) || null;
      if (!cur && spoce.row.beneficiaryname) {
        cur =
          this.cityOptions.find(
            item => item.username === spoce.row.beneficiaryname
          ) || null;
      }
      this.funddetailForm.userKey = cur
        ? cur.id
        : spoce.row.beneficiaryname || null;
      this.funddetailForm.userName = spoce.row.beneficiaryname || null;
      //打开时展示全量候选,便于直接浏览筛查
      this.optionsperformance = this.cityOptions.slice();
      this.showSelectionDialog = true;
    },
    //专家/医疗机构/费用报销机构选择
    /**
     * 确定选择:按唯一键(人员 ID)匹配候选,
     * 自动带出身份证号、银行账号、开户银行、电话、职称、人员编号、单位;
     * 单位(人员类型含 org)不写身份证号;手工输入的姓名不做带出。
     */
    ConfirmDetailDialog() {
      let tempIndex = this.funddetailForm.index;
      let tempExpertName = this.funddetailForm.userName;
      let singleDetail = this.rbDetails[tempIndex];
      const tempIndex = this.funddetailForm.index;
      const singleDetail = this.rbDetails[tempIndex];
      const key = this.funddetailForm.userKey;
      //从专家列表获取信息
      this.cityOptions.map(res => {
        if (tempExpertName == res.userName) {
          singleDetail.beneficiaryno = res.userno;
          singleDetail.bankcardno = res.bankCardNo;
          singleDetail.branchbankname = res.branchbankname;
          singleDetail.depositbank = res.depositBank;
          singleDetail.idcardno = res.idcardNo;
          singleDetail.phone = res.telephone;
          singleDetail.title = res.title;
          singleDetail.unitname = res.unitname;
          singleDetail.unitno = parseInt(res.unitno);
        }
      });
      singleDetail.beneficiaryname = tempExpertName;
      this.rbDetails[tempIndex] = singleDetail;
      if (key === null || key === undefined || key === "") {
        this.$modal.msgWarning("请先筛查并选择绩效人员,或直接输入人员姓名!");
        return;
      }
      const person = this.getPickedPerson(key);
      if (person) {
        // 命中人员库:自动带出全部信息
        const isunit = this.isUnitPerson(person);
        singleDetail.beneficiaryname = person.username;
        singleDetail.beneficiaryno = person.userno;
        singleDetail.isunit = isunit ? 1 : 0;
        singleDetail.idcardno = isunit ? "" : person.idcardno;
        singleDetail.bankcardno = person.bankcardno;
        singleDetail.branchbankname = person.branchbankname;
        singleDetail.depositbank = person.depositbank;
        singleDetail.phone = person.telephone;
        singleDetail.title = person.title;
        singleDetail.unitname = person.unitname;
        singleDetail.unitno = person.unitno;
      } else {
        // 手工输入的人员:只写姓名,身份证号/银行账号由经办人填写
        singleDetail.beneficiaryname = String(key);
        singleDetail.isunit = 0;
        this.$modal.msgWarning(
          "人员库中未找到「" +
            key +
            "」,已按手工录入处理,请自行填写身份证号、银行账号等信息。"
        );
      }
      this.$set(this.rbDetails, tempIndex, singleDetail);
      this.showSelectionDialog = false;
    },
    remoteMethod(query) {
      console.log(this.listperformancea);
      if (query !== "") {
        this.loadingperformance = true;
        setTimeout(() => {
          this.loadingperformance = false;
          this.optionsperformance = this.listperformancea.filter(item => {
            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
          });
        }, 200);
    handleUploadError() {},
    remove(file, fileList) {
      const rbDetails = [...this.rbDetails];
      if (this.activeName == 1) {
        this.fileListto.splice(this.fileListto.indexOf(file), 1);
        rbDetails[this.atpresent].annexfilesList = this.fileListto;
      } else {
        this.optionsperformance = [];
        this.invoicefileListto.splice(this.invoicefileListto.indexOf(file), 1);
        rbDetails[this.atpresent].invoicefilesList = this.invoicefileListto;
      }
    },
    // 获取请求头
    Getnetworkheader() {
      let string = window.location.href;
      if (string.includes("9091")) {
        const index = string.indexOf("9091");
        this.Networkheader = string.slice(0, index + 4); // 截取9091及其前部字符
      } else {
        const index = string.indexOf("8032");
        this.Networkheader = string.slice(0, index + 4); // 截取8032及其前部字符
      }
    },
    /**
     * 2026-10-15:上传时校验附件文件名(业务要求:不合格立即提示且不加入列表)。
     * 规则与后端 AttachmentNameValidator 同口径:必须含中文 / 去掉扩展名后主干 ≤20 字 /
     * 不含空格及 / \ : * ? " < > | # % 等特殊字符。
     */
    checkUploadFileName(file) {
      const raw = file && file.raw ? file.raw.name : file && file.name;
      const r = checkFileName(raw);
      if (!r.ok) {
        this.$modal.msgError(r.msg);
        return false;
      }
      return true;
    },
    /**
     * 2026-10-15:保存前校验整单明细附件文件名(含同一行内重名)。
     * 口径(业务确认):只校验"本次变更"的附件——老单据里已存在的不合规附件名不能把保存卡死
     * (否则老单据改一个金额都存不进去)。后端按 id 读旧记录放行历史附件;前端拿不到"哪些是历史"
     * 的权威信息,因此**仅新增单据**做保存前拦截,编辑老单据时新增的不合规附件由后端二次校验拦下。
     */
    checkDetailFileNames() {
      if (this.form && this.form.id) {
        return true;
      }
      const c = checkDetails(this.rbDetails);
      if (!c.ok) {
        this.$modal.msgError(c.msg);
        return false;
      }
      return true;
    },
    uploadSccess(response, file, fileList) {
      if (!this.checkUploadFileName(file)) {
        return;
      }
      this.rbDetails;
      const config = {
        headers: { Authorization: "Bearer " + this.ICDtoken }
      };
      const pdfimg = this.Networkheader + "/prod-api" + response.fileName;
      //获取票据信息位置
      if (this.activeName == 1) {
        if (response.code == 200) {
          this.previewpdf = true;
          fetch(pdfimg, config)
            .then(response => response.blob())
            .then(blob => {
              // 将获取的数据流转换为URL
              this.pdfimg = URL.createObjectURL(blob);
              this.pdfimgsrcList.push(URL.createObjectURL(blob));
              this.fileListto.push({
                name: file.name,
                url: URL.createObjectURL(blob)
              });
            })
            .catch(error => {
              console.error("Error loading image", error);
              return;
            });
          this.$modal.msgSuccess(response.msg);
          console.log(this.fileListto, "新增后");
          if (!this.rbDetails[this.atpresent].annexfilesList) {
            this.rbDetails[this.atpresent].annexfilesList = [];
          }
          this.rbDetails[this.atpresent].annexfilesList.push({
            name: file.name,
            url: response.fileName
          });
          this.pdftitle = "共" + this.pdfimgsrcList.length + "项";
        } else {
          console.log(response.msg);
        }
      } else {
        if (response.code == 200) {
          this.previewpdf = true;
          fetch(pdfimg, config)
            .then(response => response.blob())
            .then(blob => {
              // 将获取的数据流转换为URL
              this.invoicepdfimg = URL.createObjectURL(blob);
              this.invoicepdfimgsrcList.push(URL.createObjectURL(blob));
              this.invoicefileListto.push({
                name: file.name,
                url: URL.createObjectURL(blob)
              });
            })
            .catch(error => {
              console.error("Error loading image", error);
              return;
            });
          this.$modal.msgSuccess(response.msg);
          console.log(this.invoicefileListto, "新增后");
          if (!this.rbDetails[this.atpresent].invoicefilesList) {
            this.rbDetails[this.atpresent].invoicefilesList = [];
          }
          this.rbDetails[this.atpresent].invoicefilesList.push({
            name: file.name,
            url: response.fileName
          });
          this.pdftitle = "共" + this.invoicepdfimgsrcList.length + "项";
        }
      }
    },
    // 点击票据
    Filepopup(index, rows, row) {
      const config = {
        headers: { Authorization: "Bearer " + this.ICDtoken }
      };
      this.tableDatatop = [];
      this.fileListto = [];
      this.invoicefileListto = [];
      this.pdfimg = "";
      this.invoicepdfimg = [];
      this.pdfimgsrcList = [];
      this.invoicepdfimgsrcList = [];
      this.tableDatatop.push(row);
      this.atpresent = index;
      this.pdfVisible = true;
      if (this.rbDetails[index].annexfilesList) {
        const fetchPromises = this.rbDetails[index].annexfilesList.map(
          (value, indexson) => {
            const pdfimg = this.Networkheader + "/prod-api" + value.url;
            return fetch(pdfimg, config)
              .then(response => response.blob())
              .then(blob => {
                return {
                  name: value.name,
                  url: URL.createObjectURL(blob)
                };
              })
              .catch(error => {
                console.error("Error loading image", error);
                return null;
              });
          }
        );
        Promise.all(fetchPromises).then(fileListto => {
          this.fileListto = fileListto.filter(item => item !== null);
          this.pdfimg = this.fileListto[0].url;
          console.log(this.pdfimg, "pdfimg");
          this.pdfimgsrcList = this.fileListto.map(item => item.url);
        });
        this.previewpdf = true;
      } else {
        this.fileListto = [];
        this.pdfimg = "";
        this.pdftitle = "";
      }
      //发票
      if (this.rbDetails[index].invoicefilesList) {
        const fetchPromises = this.rbDetails[index].invoicefilesList.map(
          (value, indexson) => {
            const pdfimg = this.Networkheader + "/prod-api" + value.url;
            return fetch(pdfimg, config)
              .then(response => response.blob())
              .then(blob => {
                return {
                  name: value.name,
                  url: URL.createObjectURL(blob)
                };
              })
              .catch(error => {
                console.error("Error loading image", error);
                return null;
              });
          }
        );
        Promise.all(fetchPromises).then(invoicefileListto => {
          this.invoicefileListto = invoicefileListto.filter(
            item => item !== null
          );
          this.invoicepdfimg = this.invoicefileListto[0].url;
          console.log(this.invoicepdfimg, "invoicepdfimg");
          this.invoicepdfimgsrcList = this.invoicefileListto.map(
            item => item.url
          );
        });
        this.previewpdf = true;
      } else {
        this.invoicefileListto = [];
        this.invoicepdfimg = "";
        this.pdftitle = "";
      }
      if (this.activeName == "common") {
        this.pdftitle = "共" + this.pdfimgsrcList.length + "项";
      } else {
        this.pdftitle = "共" + this.invoicepdfimgsrcList.length + "项";
      }
      console.log(this.fileListto, "this.fileListto");
      console.log(this.rbDetails[index].annexfilesList, "annexfilesList");
    },
    // 点击已上传文件
    downFile(item) {
      if (this.activeName == 1) {
        this.pdftitle =
          "共" + this.pdfimgsrcList.length + "项,当前选中" + item.name;
        let name = item.name.split(".");
        if (name[1] == "pdf") {
          this.$modal.msgWarning("当前文件暂不支持预览");
          this.previewpdf = false;
          this.hintitle = "当前文件暂不支持预览";
        } else if (name[1] == "jpg" || "png") {
          console.log(item, "展示");
          this.previewpdf = true;
          if (item.url) {
            this.pdfimg = item.url;
          } else {
            this.pdfimg = "";
          }
        } else {
          this.hintitle = "当前文件暂不支持预览";
          this.$modal.msgWarning("当前文件暂不支持预览");
          this.previewpdf = false;
        }
      } else {
        this.pdftitle =
          "共" + this.invoicepdfimgsrcList.length + "项,当前选中" + item.name;
        let name = item.name.split(".");
        if (name[1] == "pdf") {
          this.$modal.msgWarning("当前文件暂不支持预览");
          this.previewpdf = false;
          this.hintitle = "当前文件暂不支持预览";
        } else if (name[1] == "jpg" || "png") {
          this.previewpdf = true;
          if (item.url) {
            this.invoicepdfimg = item.url;
          } else {
            this.invoicepdfimg = "";
          }
        } else {
          this.hintitle = "当前文件暂不支持预览";
          this.$modal.msgWarning("当前文件暂不支持预览");
          this.previewpdf = false;
        }
      }
    },
    getIndexInArray(arr, obj) {
      return arr.indexOf(obj);
    },
    // 发票切换
    handleClick(tab, event) {
      if (this.activeName == 1) {
        this.pdftitle = "共" + this.pdfimgsrcList.length + "项";
      } else {
        this.pdftitle = "共" + this.invoicepdfimgsrcList.length + "项";
      }
    },
    // 点击删除
    deletedowfile(row) {
      console.log(row);
      let indexvalue = "";
      if (this.activeName == 1) {
        const indexlist = this.getIndexInArray(this.pdfimgsrcList, row.url);
        this.pdfimgsrcList.splice(indexlist, 1);
        const index = this.getIndexInArray(this.fileListto, row);
        this.fileListto.splice(index, 1);
        console.log(this.rbDetails[this.atpresent].annexfilesList);
        indexvalue = this.rbDetails[this.atpresent].annexfilesList.find(
          (item, index) => {
            return item.name == row.name;
          }
        );
        console.log(indexvalue, "删除索引");
        this.rbDetails[this.atpresent].annexfilesList.splice(indexvalue, 1);
      } else {
        const indexlist = this.getIndexInArray(
          this.invoicepdfimgsrcList,
          row.url
        );
        this.invoicepdfimgsrcList.splice(indexlist, 1);
        const index = this.getIndexInArray(this.invoicefileListto, row);
        this.invoicefileListto.splice(index, 1);
        console.log(this.rbDetails[this.atpresent].invoicefilesList);
        indexvalue = this.rbDetails[this.atpresent].invoicefilesList.find(
          (item, index) => {
            return item.name == row.name;
          }
        );
        console.log(indexvalue, "删除索引");
        this.rbDetails[this.atpresent].invoicefilesList.splice(indexvalue, 1);
      }
    },
    // 点击上移
    moveupdowfile(row) {
      if (this.activeName == 1) {
        const index = this.getIndexInArray(this.fileListto, row);
        const item = this.fileListto.splice(index, 1)[0]; // 移除指定索引处的元素,并保存到item变量中
        this.fileListto.splice(index - 1, 0, item); // 将item插入到索引位置的前一位
        const indexann = this.rbDetails[
          this.atpresent
        ].annexfilesList.findIndex(item => item.name == row.name);
        const itemann = this.rbDetails[this.atpresent].annexfilesList.splice(
          indexann,
          1
        )[0]; // 移除指定索引处的元素,并保存到item变量中
        this.rbDetails[this.atpresent].annexfilesList.splice(
          indexann - 1,
          0,
          itemann
        ); // 将itemann插入到索引位置的前一位
      } else {
        const index = this.getIndexInArray(this.invoicefileListto, row);
        const item = this.invoicefileListto.splice(index, 1)[0]; // 移除指定索引处的元素,并保存到item变量中
        this.invoicefileListto.splice(index - 1, 0, item); // 将item插入到索引位置的前一位
        const indexinvo = this.rbDetails[
          this.atpresent
        ].invoicefilesList.findIndex(item => item.name == row.name);
        const iteminvo = this.rbDetails[this.atpresent].invoicefilesList.splice(
          indexinvo,
          1
        )[0]; // 移除指定索引处的元素,并保存到item变量中
        this.rbDetails[this.atpresent].invoicefilesList.splice(
          indexinvo - 1,
          0,
          iteminvo
        ); // 将iteminvo插入到索引位置的前一位
      }
    },
    Downloadfile(row) {
      console.log(row);
      window.location.href = this.Networkheader + "/prod-api" + row.url;
    },
    //表格合计
    getSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      var columnnames = [
        "applytype",
        "itemid",
        // "jxrq",
        "beneficiaryname",
        "idcardno",
        "depositbank",
        "bankcardno",
        "remark"
      ];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "合计";
          return;
        }
        //去除部分字段计算
        if (columnnames.indexOf(column.property) > -1) {
          return;
        }
        const values = data.map(item => Number(item[column.property]));
        if (!values.every(value => isNaN(value))) {
          sums[index] = values.reduce((prev, curr) => {
            const value = Number(curr);
            if (!isNaN(value)) {
              return prev + curr;
            } else {
              return prev;
            }
          }, 0);
          sums[index] = sums[index].toFixed(2); // 保留2位小数,解决小数合计列;
        } else {
          sums[index] = "";
        }
      });
      return sums;
    }
  },
@@ -1843,6 +3158,7 @@
  created() {
    //获取路由参数
    this.getroute();
    this.Getnetworkheader();
    this.getExternalList();
    this.getFeeUnitList();
    this.listperformance();
@@ -1858,7 +3174,23 @@
  destroyed() {
    window.removeEventListener("beforeunload", e => this.beforeunloadFn(e));
  }, //生命周期 - 销毁完成
  activated() { } //如果页面有keep-alive缓存功能,这个函数会触发
  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
  // 图片预览
  handleImageClick(index) {
    this.currentIndex = index;
    this.viewerVisible = true;
  },
  handleViewerClose() {
    this.viewerVisible = false;
  },
  invoiceHandleImageClick(index) {
    this.invoiceCurrentIndex = index;
    this.invoiceViewerVisible = true;
  },
  invoiceHandleViewerClose() {
    this.invoiceViewerVisible = false;
  },
};
</script>
@@ -1941,7 +3273,7 @@
  line-height: 25px;
}
::v-deep .el-checkbox.is-bordered+.el-checkbox.is-bordered {
::v-deep .el-checkbox.is-bordered + .el-checkbox.is-bordered {
  margin-left: 0 !important;
  margin-bottom: 10px;
}