|
@@ -0,0 +1,858 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="fixed-assets-table-container">
|
|
|
|
|
+ <el-table
|
|
|
|
|
+ :data="flattenedTableData"
|
|
|
|
|
+ border
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ :row-class-name="getRowClassName"
|
|
|
|
|
+ >
|
|
|
|
|
+ <!-- 序号列 -->
|
|
|
|
|
+ <el-table-column prop="seq" label="序号" width="80" align="center">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <span v-if="scope.row.isCategory" class="category-seq">
|
|
|
|
|
+ {{ scope.row.categorySeq }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span v-else>{{ scope.row.seq }}</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 项目列 -->
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="itemName"
|
|
|
|
|
+ label="项目"
|
|
|
|
|
+ min-width="200"
|
|
|
|
|
+ align="left"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <span v-if="scope.row.isCategory" class="category-name">
|
|
|
|
|
+ {{ scope.row.itemName }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-else
|
|
|
|
|
+ v-model="scope.row.itemName"
|
|
|
|
|
+ placeholder="请输入项目名称"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 计量单位列 -->
|
|
|
|
|
+ <el-table-column prop="unit" label="计量单位" width="120" align="center">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-if="!scope.row.isCategory"
|
|
|
|
|
+ v-model="scope.row.unit"
|
|
|
|
|
+ placeholder="单位"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 固定资产原值列 -->
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="originalValue"
|
|
|
|
|
+ label="固定资产原值"
|
|
|
|
|
+ width="150"
|
|
|
|
|
+ align="center"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-if="!scope.row.isCategory"
|
|
|
|
|
+ v-model="scope.row.originalValue"
|
|
|
|
|
+ placeholder="原值"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ @blur="handleCellBlur(scope.row, 'originalValue')"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 入帐或竣工验收日期列 -->
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="entryDate"
|
|
|
|
|
+ label="入帐或竣工验收日期"
|
|
|
|
|
+ width="180"
|
|
|
|
|
+ align="center"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-if="!scope.row.isCategory"
|
|
|
|
|
+ v-model="scope.row.entryDate"
|
|
|
|
|
+ type="date"
|
|
|
|
|
+ placeholder="选择日期"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ format="yyyy-MM-dd"
|
|
|
|
|
+ value-format="yyyy-MM-dd"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 折旧年限列 -->
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="depreciationPeriod"
|
|
|
|
|
+ label="折旧年限"
|
|
|
|
|
+ width="120"
|
|
|
|
|
+ align="center"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-if="!scope.row.isCategory"
|
|
|
|
|
+ v-model="scope.row.depreciationPeriod"
|
|
|
|
|
+ placeholder="年限"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ @blur="handleCellBlur(scope.row, 'depreciationPeriod')"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 折旧费列 -->
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="depreciationExpense"
|
|
|
|
|
+ label="折旧费"
|
|
|
|
|
+ width="120"
|
|
|
|
|
+ align="center"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-if="!scope.row.isCategory"
|
|
|
|
|
+ v-model="scope.row.depreciationExpense"
|
|
|
|
|
+ placeholder="费用"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ @blur="handleCellBlur(scope.row, 'depreciationExpense')"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 资金来源列 -->
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="fundSource"
|
|
|
|
|
+ label="资金来源"
|
|
|
|
|
+ width="120"
|
|
|
|
|
+ align="center"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-if="!scope.row.isCategory"
|
|
|
|
|
+ v-model="scope.row.fundSource"
|
|
|
|
|
+ placeholder="来源"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 备注列 -->
|
|
|
|
|
+ <el-table-column prop="remark" label="备注" min-width="150">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-if="!scope.row.isCategory"
|
|
|
|
|
+ v-model="scope.row.remark"
|
|
|
|
|
+ placeholder="备注"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 操作列 -->
|
|
|
|
|
+ <el-table-column label="操作" width="100" align="center" fixed="right">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <div v-if="scope.row.isCategory" class="operation-buttons">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ icon="el-icon-plus"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ @click="handleAddRow(scope.row)"
|
|
|
|
|
+ />
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ icon="el-icon-minus"
|
|
|
|
|
+ :disabled="isViewMode"
|
|
|
|
|
+ @click="handleDeleteRow(scope.row)"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+ import { Message } from 'element-ui'
|
|
|
|
|
+
|
|
|
|
|
+ export default {
|
|
|
|
|
+ name: 'FixedAssetsTable',
|
|
|
|
|
+ props: {
|
|
|
|
|
+ // 表格数据配置(嵌套结构)
|
|
|
|
|
+ tableItems: {
|
|
|
|
|
+ type: Array,
|
|
|
|
|
+ default: () => [],
|
|
|
|
|
+ },
|
|
|
|
|
+ // 是否有保存的数据
|
|
|
|
|
+ savedData: {
|
|
|
|
|
+ type: Object,
|
|
|
|
|
+ default: () => ({}),
|
|
|
|
|
+ },
|
|
|
|
|
+ // 是否查看模式
|
|
|
|
|
+ isViewMode: {
|
|
|
|
|
+ type: Boolean,
|
|
|
|
|
+ default: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ // 嵌套的表格数据
|
|
|
|
|
+ fixedAssetsData: [],
|
|
|
|
|
+ // 验证错误
|
|
|
|
|
+ validationErrors: [],
|
|
|
|
|
+ // 扁平化的表格数据(响应式)
|
|
|
|
|
+ flattenedData: [],
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ // 扁平化的表格数据(从嵌套结构生成)
|
|
|
|
|
+ flattenedTableData() {
|
|
|
|
|
+ return this.flattenedData
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ watch: {
|
|
|
|
|
+ tableItems: {
|
|
|
|
|
+ handler(newVal) {
|
|
|
|
|
+ if (newVal && newVal.length > 0) {
|
|
|
|
|
+ this.fixedAssetsData = this.deepClone(newVal)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.fixedAssetsData = this.getDefaultTableData()
|
|
|
|
|
+ }
|
|
|
|
|
+ // 重新生成扁平数据
|
|
|
|
|
+ this.generateFlattenedData()
|
|
|
|
|
+ },
|
|
|
|
|
+ immediate: true,
|
|
|
|
|
+ deep: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ savedData: {
|
|
|
|
|
+ handler() {
|
|
|
|
|
+ // 数据变化时重新生成扁平数据
|
|
|
|
|
+ this.generateFlattenedData()
|
|
|
|
|
+ },
|
|
|
|
|
+ deep: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ // 生成扁平数据
|
|
|
|
|
+ generateFlattenedData() {
|
|
|
|
|
+ const result = []
|
|
|
|
|
+ let seq = 1
|
|
|
|
|
+
|
|
|
|
|
+ const processItem = (item, parentCategory = null) => {
|
|
|
|
|
+ if (item.isCategory) {
|
|
|
|
|
+ // 分类行
|
|
|
|
|
+ result.push({
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ seq: item.categorySeq || item.id,
|
|
|
|
|
+ isCategory: true,
|
|
|
|
|
+ categorySeq: item.categorySeq || item.id,
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 处理分类下的子项
|
|
|
|
|
+ if (item.children && Array.isArray(item.children)) {
|
|
|
|
|
+ item.children.forEach((child) => {
|
|
|
|
|
+ processItem(child, item)
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 普通行
|
|
|
|
|
+ const rowData = {
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ seq: seq++,
|
|
|
|
|
+ isCategory: false,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有父分类,设置分类信息
|
|
|
|
|
+ if (parentCategory) {
|
|
|
|
|
+ rowData.categoryId = parentCategory.id
|
|
|
|
|
+ rowData.categorySeq =
|
|
|
|
|
+ parentCategory.categorySeq || parentCategory.id
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化字段
|
|
|
|
|
+ if (rowData.itemName === undefined) rowData.itemName = ''
|
|
|
|
|
+ if (rowData.unit === undefined) rowData.unit = ''
|
|
|
|
|
+ if (rowData.originalValue === undefined) rowData.originalValue = ''
|
|
|
|
|
+ if (rowData.entryDate === undefined) rowData.entryDate = ''
|
|
|
|
|
+ if (rowData.depreciationPeriod === undefined)
|
|
|
|
|
+ rowData.depreciationPeriod = ''
|
|
|
|
|
+ if (rowData.depreciationExpense === undefined)
|
|
|
|
|
+ rowData.depreciationExpense = ''
|
|
|
|
|
+ if (rowData.fundSource === undefined) rowData.fundSource = ''
|
|
|
|
|
+ if (rowData.remark === undefined) rowData.remark = ''
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有保存的数据,填充值
|
|
|
|
|
+ if (this.savedData) {
|
|
|
|
|
+ // 从保存的数据中查找对应的值
|
|
|
|
|
+ const savedItem = this.findSavedItemById(item.id)
|
|
|
|
|
+ if (savedItem) {
|
|
|
|
|
+ Object.keys(savedItem).forEach((key) => {
|
|
|
|
|
+ if (savedItem[key] !== undefined && key !== 'id') {
|
|
|
|
|
+ rowData[key] = savedItem[key]
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ result.push(rowData)
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有子项,递归处理
|
|
|
|
|
+ if (item.children && Array.isArray(item.children)) {
|
|
|
|
|
+ item.children.forEach((child) => {
|
|
|
|
|
+ processItem(child, item)
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理所有项
|
|
|
|
|
+ this.fixedAssetsData.forEach((item) => {
|
|
|
|
|
+ processItem(item)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 使用 Vue.set 确保响应式
|
|
|
|
|
+ this.$set(this, 'flattenedData', result)
|
|
|
|
|
+ },
|
|
|
|
|
+ // 深拷贝
|
|
|
|
|
+ deepClone(obj) {
|
|
|
|
|
+ if (obj === null || typeof obj !== 'object') return obj
|
|
|
|
|
+ if (obj instanceof Date) return new Date(obj.getTime())
|
|
|
|
|
+ if (obj instanceof Array) return obj.map((item) => this.deepClone(item))
|
|
|
|
|
+ if (typeof obj === 'object') {
|
|
|
|
|
+ const clonedObj = {}
|
|
|
|
|
+ for (const key in obj) {
|
|
|
|
|
+ if (obj.hasOwnProperty(key)) {
|
|
|
|
|
+ clonedObj[key] = this.deepClone(obj[key])
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return clonedObj
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 获取默认表格数据
|
|
|
|
|
+ getDefaultTableData() {
|
|
|
|
|
+ return [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'I',
|
|
|
|
|
+ itemName: '房屋建筑物',
|
|
|
|
|
+ isCategory: true,
|
|
|
|
|
+ categorySeq: 'I',
|
|
|
|
|
+ children: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'I-1',
|
|
|
|
|
+ itemName: '办公用房',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'I-2',
|
|
|
|
|
+ itemName: '教保用房',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'I-3',
|
|
|
|
|
+ itemName: '幼儿宿舍用房',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'I-4',
|
|
|
|
|
+ itemName: '其它',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'II',
|
|
|
|
|
+ itemName: '交通运输工具',
|
|
|
|
|
+ isCategory: true,
|
|
|
|
|
+ categorySeq: 'II',
|
|
|
|
|
+ children: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'II-1',
|
|
|
|
|
+ itemName: '车辆',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'III',
|
|
|
|
|
+ itemName: '教保专用设备',
|
|
|
|
|
+ isCategory: true,
|
|
|
|
|
+ categorySeq: 'III',
|
|
|
|
|
+ children: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'III-1',
|
|
|
|
|
+ itemName: '电教',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'III-2',
|
|
|
|
|
+ itemName: '文体',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'IV',
|
|
|
|
|
+ itemName: '办公设备',
|
|
|
|
|
+ isCategory: true,
|
|
|
|
|
+ categorySeq: 'IV',
|
|
|
|
|
+ children: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'IV-1',
|
|
|
|
|
+ itemName: '电脑',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'V',
|
|
|
|
|
+ itemName: '其它固定资产',
|
|
|
|
|
+ isCategory: true,
|
|
|
|
|
+ categorySeq: 'V',
|
|
|
|
|
+ children: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'V-1',
|
|
|
|
|
+ itemName: '空调',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'V-2',
|
|
|
|
|
+ itemName: '家电',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'V-3',
|
|
|
|
|
+ itemName: '供水系统',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'V-4',
|
|
|
|
|
+ itemName: '洗涤用具',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'V-5',
|
|
|
|
|
+ itemName: '家具',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'V-6',
|
|
|
|
|
+ itemName: '炊事用具',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'V-7',
|
|
|
|
|
+ itemName: '其它',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ // 获取行样式类名
|
|
|
|
|
+ getRowClassName({ row }) {
|
|
|
|
|
+ if (row.isCategory) {
|
|
|
|
|
+ return 'category-row'
|
|
|
|
|
+ }
|
|
|
|
|
+ return ''
|
|
|
|
|
+ },
|
|
|
|
|
+ // 添加行
|
|
|
|
|
+ handleAddRow(row) {
|
|
|
|
|
+ // 找到对应的分类
|
|
|
|
|
+ const category = this.findCategoryById(row.id)
|
|
|
|
|
+ if (category) {
|
|
|
|
|
+ // 生成新的项目ID
|
|
|
|
|
+ const newId = `${row.id}-${Date.now()}`
|
|
|
|
|
+ const newItem = {
|
|
|
|
|
+ id: newId,
|
|
|
|
|
+ itemName: '',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ originalValue: '',
|
|
|
|
|
+ entryDate: '',
|
|
|
|
|
+ depreciationPeriod: '',
|
|
|
|
|
+ depreciationExpense: '',
|
|
|
|
|
+ fundSource: '',
|
|
|
|
|
+ remark: '',
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 在分类的 children 数组末尾添加新行
|
|
|
|
|
+ if (!category.children) {
|
|
|
|
|
+ this.$set(category, 'children', [])
|
|
|
|
|
+ }
|
|
|
|
|
+ category.children.push(newItem)
|
|
|
|
|
+
|
|
|
|
|
+ // 重新生成扁平数据
|
|
|
|
|
+ this.generateFlattenedData()
|
|
|
|
|
+ Message.success('添加行成功')
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 删除行(删除分类下的最后一个子项)
|
|
|
|
|
+ handleDeleteRow(row) {
|
|
|
|
|
+ // row 是分类行,需要找到该分类下的子项
|
|
|
|
|
+ const category = this.findCategoryById(row.id)
|
|
|
|
|
+ if (category && category.children && category.children.length > 0) {
|
|
|
|
|
+ // 删除最后一个子项
|
|
|
|
|
+ category.children.pop()
|
|
|
|
|
+ // 重新生成扁平数据
|
|
|
|
|
+ this.generateFlattenedData()
|
|
|
|
|
+ Message.success('删除成功')
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Message.warning('该分类下没有可删除的行')
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 根据ID在保存的数据中查找
|
|
|
|
|
+ findSavedItemById(id) {
|
|
|
|
|
+ if (!this.savedData) return null
|
|
|
|
|
+
|
|
|
|
|
+ // 递归查找
|
|
|
|
|
+ const findInArray = (items) => {
|
|
|
|
|
+ for (const item of items) {
|
|
|
|
|
+ if (item.id === id) {
|
|
|
|
|
+ return item
|
|
|
|
|
+ }
|
|
|
|
|
+ if (item.children && Array.isArray(item.children)) {
|
|
|
|
|
+ const found = findInArray(item.children)
|
|
|
|
|
+ if (found) return found
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return null
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果 savedData 是数组
|
|
|
|
|
+ if (Array.isArray(this.savedData)) {
|
|
|
|
|
+ return findInArray(this.savedData)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果 savedData 是对象,尝试查找
|
|
|
|
|
+ if (typeof this.savedData === 'object') {
|
|
|
|
|
+ // 可能是一个映射对象,key 是 id
|
|
|
|
|
+ if (this.savedData[id]) {
|
|
|
|
|
+ return this.savedData[id]
|
|
|
|
|
+ }
|
|
|
|
|
+ // 或者是嵌套结构
|
|
|
|
|
+ return findInArray([this.savedData])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null
|
|
|
|
|
+ },
|
|
|
|
|
+ // 根据ID查找分类
|
|
|
|
|
+ findCategoryById(id) {
|
|
|
|
|
+ const findInArray = (items) => {
|
|
|
|
|
+ for (const item of items) {
|
|
|
|
|
+ if (item.id === id) {
|
|
|
|
|
+ return item
|
|
|
|
|
+ }
|
|
|
|
|
+ if (item.children && Array.isArray(item.children)) {
|
|
|
|
|
+ const found = findInArray(item.children)
|
|
|
|
|
+ if (found) return found
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return null
|
|
|
|
|
+ }
|
|
|
|
|
+ return findInArray(this.fixedAssetsData)
|
|
|
|
|
+ },
|
|
|
|
|
+ // 单元格失焦验证
|
|
|
|
|
+ handleCellBlur(row, field) {
|
|
|
|
|
+ // 实时验证格式
|
|
|
|
|
+ if (field === 'originalValue' || field === 'depreciationExpense') {
|
|
|
|
|
+ const value = row[field]
|
|
|
|
|
+ if (value && !/^\d+(\.\d+)?$/.test(value)) {
|
|
|
|
|
+ Message.warning(
|
|
|
|
|
+ `${this.getFieldLabel(field)}格式不正确,请输入数字`
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (field === 'depreciationPeriod') {
|
|
|
|
|
+ const value = row[field]
|
|
|
|
|
+ if (value && !/^\d+$/.test(value)) {
|
|
|
|
|
+ Message.warning(`${this.getFieldLabel(field)}必须是正整数`)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 获取字段标签
|
|
|
|
|
+ getFieldLabel(field) {
|
|
|
|
|
+ const labels = {
|
|
|
|
|
+ originalValue: '固定资产原值',
|
|
|
|
|
+ depreciationPeriod: '折旧年限',
|
|
|
|
|
+ depreciationExpense: '折旧费',
|
|
|
|
|
+ }
|
|
|
|
|
+ return labels[field] || field
|
|
|
|
|
+ },
|
|
|
|
|
+ // 验证表单
|
|
|
|
|
+ validate() {
|
|
|
|
|
+ this.validationErrors = []
|
|
|
|
|
+ const errors = []
|
|
|
|
|
+
|
|
|
|
|
+ // 验证扁平数据(因为用户编辑的是扁平数据)
|
|
|
|
|
+ const flatData = this.flattenedTableData
|
|
|
|
|
+ flatData.forEach((item, index) => {
|
|
|
|
|
+ if (!item.isCategory) {
|
|
|
|
|
+ // 非空验证
|
|
|
|
|
+ if (!item.itemName || String(item.itemName).trim() === '') {
|
|
|
|
|
+ errors.push(`第${item.seq}行:项目名称不能为空`)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!item.unit || String(item.unit).trim() === '') {
|
|
|
|
|
+ errors.push(`第${item.seq}行:计量单位不能为空`)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (
|
|
|
|
|
+ !item.originalValue ||
|
|
|
|
|
+ String(item.originalValue).trim() === ''
|
|
|
|
|
+ ) {
|
|
|
|
|
+ errors.push(`第${item.seq}行:固定资产原值不能为空`)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!item.entryDate || String(item.entryDate).trim() === '') {
|
|
|
|
|
+ errors.push(`第${item.seq}行:入帐或竣工验收日期不能为空`)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (
|
|
|
|
|
+ !item.depreciationPeriod ||
|
|
|
|
|
+ String(item.depreciationPeriod).trim() === ''
|
|
|
|
|
+ ) {
|
|
|
|
|
+ errors.push(`第${item.seq}行:折旧年限不能为空`)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (
|
|
|
|
|
+ !item.depreciationExpense ||
|
|
|
|
|
+ String(item.depreciationExpense).trim() === ''
|
|
|
|
|
+ ) {
|
|
|
|
|
+ errors.push(`第${item.seq}行:折旧费不能为空`)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!item.fundSource || String(item.fundSource).trim() === '') {
|
|
|
|
|
+ errors.push(`第${item.seq}行:资金来源不能为空`)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 格式验证
|
|
|
|
|
+ if (
|
|
|
|
|
+ item.originalValue &&
|
|
|
|
|
+ String(item.originalValue).trim() !== '' &&
|
|
|
|
|
+ !/^\d+(\.\d+)?$/.test(String(item.originalValue))
|
|
|
|
|
+ ) {
|
|
|
|
|
+ errors.push(`第${item.seq}行:固定资产原值格式不正确,请输入数字`)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (
|
|
|
|
|
+ item.depreciationPeriod &&
|
|
|
|
|
+ String(item.depreciationPeriod).trim() !== '' &&
|
|
|
|
|
+ !/^\d+$/.test(String(item.depreciationPeriod))
|
|
|
|
|
+ ) {
|
|
|
|
|
+ errors.push(`第${item.seq}行:折旧年限必须是正整数`)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (
|
|
|
|
|
+ item.depreciationExpense &&
|
|
|
|
|
+ String(item.depreciationExpense).trim() !== '' &&
|
|
|
|
|
+ !/^\d+(\.\d+)?$/.test(String(item.depreciationExpense))
|
|
|
|
|
+ ) {
|
|
|
|
|
+ errors.push(`第${item.seq}行:折旧费格式不正确,请输入数字`)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ this.validationErrors = errors
|
|
|
|
|
+ return errors.length === 0
|
|
|
|
|
+ },
|
|
|
|
|
+ // 获取表格数据(用于保存)
|
|
|
|
|
+ // 需要将扁平数据同步回嵌套结构
|
|
|
|
|
+ getTableData() {
|
|
|
|
|
+ // 同步扁平数据的修改到嵌套结构
|
|
|
|
|
+ const flatData = this.flattenedData
|
|
|
|
|
+ const syncDataToNested = (items) => {
|
|
|
|
|
+ return items.map((item) => {
|
|
|
|
|
+ if (item.isCategory) {
|
|
|
|
|
+ // 分类行
|
|
|
|
|
+ const newItem = { ...item }
|
|
|
|
|
+ if (item.children && Array.isArray(item.children)) {
|
|
|
|
|
+ newItem.children = syncDataToNested(item.children)
|
|
|
|
|
+ }
|
|
|
|
|
+ return newItem
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 普通行,从扁平数据中同步
|
|
|
|
|
+ const flatItem = flatData.find(
|
|
|
|
|
+ (f) => f.id === item.id && !f.isCategory
|
|
|
|
|
+ )
|
|
|
|
|
+ if (flatItem) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ itemName: flatItem.itemName,
|
|
|
|
|
+ unit: flatItem.unit,
|
|
|
|
|
+ originalValue: flatItem.originalValue,
|
|
|
|
|
+ entryDate: flatItem.entryDate,
|
|
|
|
|
+ depreciationPeriod: flatItem.depreciationPeriod,
|
|
|
|
|
+ depreciationExpense: flatItem.depreciationExpense,
|
|
|
|
|
+ fundSource: flatItem.fundSource,
|
|
|
|
|
+ remark: flatItem.remark,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return item
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return syncDataToNested(this.fixedAssetsData)
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+ .fixed-assets-table-container {
|
|
|
|
|
+ // 分类行样式
|
|
|
|
|
+ ::v-deep .category-row {
|
|
|
|
|
+ background-color: #f5f7fa !important;
|
|
|
|
|
+
|
|
|
|
|
+ td {
|
|
|
|
|
+ background-color: #f5f7fa !important;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .category-name {
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .category-seq {
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 操作按钮样式
|
|
|
|
|
+ .operation-buttons {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ gap: 5px;
|
|
|
|
|
+
|
|
|
|
|
+ .el-button {
|
|
|
|
|
+ padding: 5px;
|
|
|
|
|
+ min-width: 24px;
|
|
|
|
|
+ height: 24px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ background-color: #000;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background-color: #333;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ i {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 输入框样式
|
|
|
|
|
+ ::v-deep .el-input__inner {
|
|
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+
|
|
|
|
|
+ &:focus {
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 日期选择器样式
|
|
|
|
|
+ ::v-deep .el-date-editor {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+</style>
|