|
|
@@ -49,7 +49,12 @@
|
|
|
size="mini"
|
|
|
format="yyyy-MM-dd"
|
|
|
value-format="yyyy-MM-dd"
|
|
|
- :disabled="isViewMode"
|
|
|
+ :disabled="
|
|
|
+ isViewMode ||
|
|
|
+ scope.row.notDeletable === true ||
|
|
|
+ scope.row.fromTemplate === true ||
|
|
|
+ scope.row.notEditable === true
|
|
|
+ "
|
|
|
style="width: 100%"
|
|
|
/>
|
|
|
<el-input
|
|
|
@@ -57,7 +62,12 @@
|
|
|
v-model="scope.row[column.prop]"
|
|
|
:placeholder="column.placeholder || '请输入' + column.label"
|
|
|
size="mini"
|
|
|
- :disabled="isViewMode"
|
|
|
+ :disabled="
|
|
|
+ isViewMode ||
|
|
|
+ scope.row.notDeletable === true ||
|
|
|
+ scope.row.fromTemplate === true ||
|
|
|
+ scope.row.notEditable === true
|
|
|
+ "
|
|
|
@blur="handleCellBlur(scope.row, column.prop)"
|
|
|
/>
|
|
|
</template>
|
|
|
@@ -96,7 +106,12 @@
|
|
|
type="text"
|
|
|
size="mini"
|
|
|
icon="el-icon-minus"
|
|
|
- :disabled="isViewMode"
|
|
|
+ :disabled="
|
|
|
+ isViewMode ||
|
|
|
+ scope.row.notDeletable === true ||
|
|
|
+ scope.row.fromTemplate === true ||
|
|
|
+ scope.row.notEditable === true
|
|
|
+ "
|
|
|
@click="handleDeleteChildRow(scope.row)"
|
|
|
/>
|
|
|
</div>
|
|
|
@@ -229,6 +244,8 @@
|
|
|
// 不使用假数据,等待接口返回数据
|
|
|
this.fixedAssetsData = []
|
|
|
}
|
|
|
+ // 在渲染前将传入的子项标记为只读
|
|
|
+ this.markInitialChildrenReadonly()
|
|
|
// 重新生成扁平数据
|
|
|
this.generateFlattenedData()
|
|
|
},
|
|
|
@@ -254,6 +271,8 @@
|
|
|
} else {
|
|
|
this.fixedAssetsData = []
|
|
|
}
|
|
|
+ // 在渲染前将传入的子项标记为只读
|
|
|
+ this.markInitialChildrenReadonly()
|
|
|
// 数据变化时重新生成扁平数据
|
|
|
this.generateFlattenedData()
|
|
|
},
|
|
|
@@ -262,6 +281,21 @@
|
|
|
},
|
|
|
},
|
|
|
methods: {
|
|
|
+ // 将传入的子项标记为只读(不可编辑/删除),新增的行不受影响
|
|
|
+ markInitialChildrenReadonly() {
|
|
|
+ const data = this.fixedAssetsData || []
|
|
|
+ data.forEach((node) => {
|
|
|
+ if (!node || typeof node !== 'object') return
|
|
|
+ const children = Array.isArray(node.children) ? node.children : []
|
|
|
+ children.forEach((child) => {
|
|
|
+ if (!child || typeof child !== 'object') return
|
|
|
+ // 仅标记已有的传入子项(保留模板标记)
|
|
|
+ if (child.notEditable !== false) {
|
|
|
+ child.notEditable = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
// 生成扁平数据
|
|
|
generateFlattenedData() {
|
|
|
// 先同步扁平数据中的修改到嵌套结构,避免数据丢失
|
|
|
@@ -606,6 +640,11 @@
|
|
|
},
|
|
|
// 删除子项(点击子项行的减号删除当前这条)
|
|
|
handleDeleteChildRow(row) {
|
|
|
+ // 模板数据不可删除
|
|
|
+ if (row && (row.notDeletable === true || row.fromTemplate === true)) {
|
|
|
+ Message.warning('该行由模板生成,无法删除')
|
|
|
+ return
|
|
|
+ }
|
|
|
// 先同步扁平数据中的修改到嵌套结构,避免数据丢失
|
|
|
this.syncFlattenedDataToNested()
|
|
|
const childRowid = row.rowid || row.rowId || row.id
|
|
|
@@ -1081,6 +1120,12 @@
|
|
|
},
|
|
|
// 保存数据(调用 saveSingleRecordSurvey 接口)
|
|
|
async saveData() {
|
|
|
+ // 保存前校验
|
|
|
+ const validationErrors = this.validateBeforeSave()
|
|
|
+ if (validationErrors && validationErrors.length > 0) {
|
|
|
+ Message.error('表单验证失败,请检查后再保存')
|
|
|
+ return false
|
|
|
+ }
|
|
|
try {
|
|
|
// 格式化保存数据为接口需要的格式
|
|
|
const saveData = []
|
|
|
@@ -1175,7 +1220,81 @@
|
|
|
return false
|
|
|
}
|
|
|
},
|
|
|
- // 判断是否为分类行
|
|
|
+ // 保存前验证
|
|
|
+ validateBeforeSave() {
|
|
|
+ const errors = []
|
|
|
+ const categories = Array.isArray(this.fixedAssetsData)
|
|
|
+ ? this.fixedAssetsData
|
|
|
+ : []
|
|
|
+
|
|
|
+ categories.forEach((category) => {
|
|
|
+ const items = Array.isArray(category.items) ? category.items : []
|
|
|
+ items.forEach((item, index) => {
|
|
|
+ const rowNum = index + 1
|
|
|
+ // 必填校验
|
|
|
+ if (!item.name) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:项目名称不能为空`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ if (!item.unit) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:计量单位不能为空`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ item.originalValue === '' ||
|
|
|
+ item.originalValue === undefined ||
|
|
|
+ item.originalValue === null
|
|
|
+ ) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:固定资产原值不能为空`
|
|
|
+ )
|
|
|
+ } else if (isNaN(Number(item.originalValue))) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:固定资产原值必须为数字`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ if (!item.entryDate) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:入帐或竣工验收日期不能为空`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ item.depreciationPeriod === '' ||
|
|
|
+ item.depreciationPeriod === undefined ||
|
|
|
+ item.depreciationPeriod === null
|
|
|
+ ) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:折旧年限不能为空`
|
|
|
+ )
|
|
|
+ } else if (isNaN(Number(item.depreciationPeriod))) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:折旧年限必须为数字`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ item.depreciationExpense === '' ||
|
|
|
+ item.depreciationExpense === undefined ||
|
|
|
+ item.depreciationExpense === null
|
|
|
+ ) {
|
|
|
+ errors.push(`${category.category} 第${rowNum}行:折旧费不能为空`)
|
|
|
+ } else if (isNaN(Number(item.depreciationExpense))) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:折旧费必须为数字`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ if (!item.fundSource) {
|
|
|
+ errors.push(
|
|
|
+ `${category.category} 第${rowNum}行:资金来源不能为空`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ this.validationErrors = errors
|
|
|
+ return errors
|
|
|
+ },
|
|
|
isCategoryItem(item) {
|
|
|
if (!item) return false
|
|
|
const flag = item.isCategory
|